std::forward 表现不同
std::forward acting differently
我目前正在学习 C++ 中的完美转发,我遇到了一些让我困惑的事情。很确定这是愚蠢的事情。当我在左值上使用 std::forward 时,它使用了右值函数。这是一个非常糟糕的解释,所以我只展示代码。
#include <iostream>
void check(int&& other) {
std::cout << "Rvalue" << std::endl;
}
void check(int& other) {
std::cout << "Lvalue" << std::endl;
}
void call(int& other) {
check(std::forward<int>(other));
}
int main()
{
int i = 4;
call(i);
}
这会输出“右值”。请帮助我了解原因。
std::forward()
并不完全是魔法。这是必须为其提供具有适当引用类别(右值引用、左值引用、无引用)的适当类型的原因之一。
通常,您从模板参数中获取类型。如果它是一个 auto&&
参数(C++14 lambda、C++20 缩写模板或概念的使用),则使用 decltype()
从函数参数中获取它。
手动指定它有效,但违背了使用该功能的精神。 std::move()
或者参数本身在这种情况下更容易使用,具体取决于您指定的模板参数。
并且由于引用折叠和 std::forward()
的定义方式,Type
和 Type&&
都会导致右值引用,而 Type&
会导致左值-参考。
模板使用“完美转发”,即:
template<typename T>
void func(T && arg)
{
func2(std::forward<T>(arg));
}
在模板上下文之外,最终结果会发生巨大变化。 std::forward
所做的只是 return static_cast<T &&>
,因此您的 call
函数只不过是:
void call(int& other) {
check(static_cast<int &&>(other));
}
因此你得到一个右值。这在模板中工作不同的原因是因为 &&
模板参数是 转发引用 (左值或一个右值推导的引用,取决于在该参数中删除的内容),并且因为 reference collapsing rules。简而言之,当在模板上下文中使用时,最终结果是:
T
被推断为左值或右值引用,具体取决于参数是什么。
如果T
是左值引用,static_cast<T &&>
的结果是左值引用,如果T
是右值引用,则结果是右值引用,由于引用折叠规则。
最终结果是转发了相同类型的引用。但这仅适用于模板上下文,因为它需要转发引用语义和引用折叠规则才能正常工作恰到好处。
我目前正在学习 C++ 中的完美转发,我遇到了一些让我困惑的事情。很确定这是愚蠢的事情。当我在左值上使用 std::forward 时,它使用了右值函数。这是一个非常糟糕的解释,所以我只展示代码。
#include <iostream>
void check(int&& other) {
std::cout << "Rvalue" << std::endl;
}
void check(int& other) {
std::cout << "Lvalue" << std::endl;
}
void call(int& other) {
check(std::forward<int>(other));
}
int main()
{
int i = 4;
call(i);
}
这会输出“右值”。请帮助我了解原因。
std::forward()
并不完全是魔法。这是必须为其提供具有适当引用类别(右值引用、左值引用、无引用)的适当类型的原因之一。
通常,您从模板参数中获取类型。如果它是一个 auto&&
参数(C++14 lambda、C++20 缩写模板或概念的使用),则使用 decltype()
从函数参数中获取它。
手动指定它有效,但违背了使用该功能的精神。 std::move()
或者参数本身在这种情况下更容易使用,具体取决于您指定的模板参数。
并且由于引用折叠和 std::forward()
的定义方式,Type
和 Type&&
都会导致右值引用,而 Type&
会导致左值-参考。
模板使用“完美转发”,即:
template<typename T>
void func(T && arg)
{
func2(std::forward<T>(arg));
}
在模板上下文之外,最终结果会发生巨大变化。 std::forward
所做的只是 return static_cast<T &&>
,因此您的 call
函数只不过是:
void call(int& other) {
check(static_cast<int &&>(other));
}
因此你得到一个右值。这在模板中工作不同的原因是因为 &&
模板参数是 转发引用 (左值或一个右值推导的引用,取决于在该参数中删除的内容),并且因为 reference collapsing rules。简而言之,当在模板上下文中使用时,最终结果是:
T
被推断为左值或右值引用,具体取决于参数是什么。如果
T
是左值引用,static_cast<T &&>
的结果是左值引用,如果T
是右值引用,则结果是右值引用,由于引用折叠规则。
最终结果是转发了相同类型的引用。但这仅适用于模板上下文,因为它需要转发引用语义和引用折叠规则才能正常工作恰到好处。