转发引用和参数推导
Forwarding reference and argument deduction
我想深入了解一下完美转发,遇到了一个我自己也想不通的问题。
假设这段代码:
void fun(int& i) {
std::cout << "int&" << std::endl;
}
void fun(int&& i) {
std::cout << "int&&" << std::endl;
}
template <typename T>
void wrapper(T&& i) {
fun(i);
}
int main()
{
wrapper(4);
}
它打印 int&
。要解决这个问题,应该使用 std::forward。这很清楚。不清楚的是为什么会这样。
上面的代码展开后是:
void fun(int & i)
{
std::operator<<(std::cout, "int&").operator<<(std::endl);
}
void fun(int && i)
{
std::operator<<(std::cout, "int&&").operator<<(std::endl);
}
template <typename T>
void wrapper(T&& i) {
fun(i);
}
/* First instantiated from: insights.cpp:21 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void wrapper<int>(int && i)
{
fun(i);
}
#endif
int main()
{
wrapper(4);
return 0;
}
所以 i
的右值类型应该是 int&&
。问题是:为什么我在这里需要 std::forward 因为编译器已经知道 i
是 int&&
而不是 int&
但仍然调用 fun(it&)
?
why do I need std::forward
here since compiler already knows that i is
int&&
not int&
but still calls fun(it&)
?
i
的类型是 int&&
,但 i
本身是一个 lvalue。因此,当您调用 fun(i)
时,由于 i
本身是一个 左值 ,编译器将选择 fun(int &)
.
如果你想调用fun(int &&)
,你可以使用std::move
将其转换为右值
fun(std::move(i));
why do I need std::forward here since compiler already knows that i is int&& not int& but still calls fun(it&)?
因为 i
当使用 as/in 表达式如调用 fun(i)
是一个 左值 。即当使用as/in表达式时i
的值类别是lvalue
。因此调用 fun(i)
选择第一个重载 (void fun(int&)
).
另一方面,i
的 声明类型 是 int&&
即 int
.[=20 的右值引用=]
类型和 value categories 是不同的东西。
Each C++ expression (an operator with its operands, a literal, a variable name, etc.) is characterized by two independent properties: a type and a value category.
i
,变量名,是左值表达式,连变量的类型都是rvalue-reference.
The following expressions are lvalue expressions:
- the name of a variable, ... Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;
- ...
这就是我们应该使用 std::forward
to preserve the original value category of a forwarding reference 参数的原因。
我想深入了解一下完美转发,遇到了一个我自己也想不通的问题。 假设这段代码:
void fun(int& i) {
std::cout << "int&" << std::endl;
}
void fun(int&& i) {
std::cout << "int&&" << std::endl;
}
template <typename T>
void wrapper(T&& i) {
fun(i);
}
int main()
{
wrapper(4);
}
它打印 int&
。要解决这个问题,应该使用 std::forward。这很清楚。不清楚的是为什么会这样。
上面的代码展开后是:
void fun(int & i)
{
std::operator<<(std::cout, "int&").operator<<(std::endl);
}
void fun(int && i)
{
std::operator<<(std::cout, "int&&").operator<<(std::endl);
}
template <typename T>
void wrapper(T&& i) {
fun(i);
}
/* First instantiated from: insights.cpp:21 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void wrapper<int>(int && i)
{
fun(i);
}
#endif
int main()
{
wrapper(4);
return 0;
}
所以 i
的右值类型应该是 int&&
。问题是:为什么我在这里需要 std::forward 因为编译器已经知道 i
是 int&&
而不是 int&
但仍然调用 fun(it&)
?
why do I need
std::forward
here since compiler already knows that i isint&&
notint&
but still callsfun(it&)
?
i
的类型是 int&&
,但 i
本身是一个 lvalue。因此,当您调用 fun(i)
时,由于 i
本身是一个 左值 ,编译器将选择 fun(int &)
.
如果你想调用fun(int &&)
,你可以使用std::move
将其转换为右值
fun(std::move(i));
why do I need std::forward here since compiler already knows that i is int&& not int& but still calls fun(it&)?
因为 i
当使用 as/in 表达式如调用 fun(i)
是一个 左值 。即当使用as/in表达式时i
的值类别是lvalue
。因此调用 fun(i)
选择第一个重载 (void fun(int&)
).
另一方面,i
的 声明类型 是 int&&
即 int
.[=20 的右值引用=]
类型和 value categories 是不同的东西。
Each C++ expression (an operator with its operands, a literal, a variable name, etc.) is characterized by two independent properties: a type and a value category.
i
,变量名,是左值表达式,连变量的类型都是rvalue-reference.
The following expressions are lvalue expressions:
- the name of a variable, ... Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression;
- ...
这就是我们应该使用 std::forward
to preserve the original value category of a forwarding reference 参数的原因。