由于一般问题“如何std::forward工作”太复杂,我决定从一个特定示例的问题开始:
#include <utility>
#include <iostream>
namespace
{
void foo(const int&)
{
std::cout << "const l-value" << std::endl;
}
void foo(int&)
{
std::cout << "l-value" << std::endl;
}
void foo(int&&)
{
std::cout << "r-value" << std::endl;
}
template <typename T>
void deduce(T&& x)
{
//foo(std::forward<T>(x));
foo(x);
}
}
int main()
{
deduce(1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
l-value
Run Code Online (Sandbox Code Playgroud)
为什么?
我们传递 r 值,并且 的参数deduce是 r 值,对吧?为什么foo(int&)叫?
当我直接打电话时
foo(1);
Run Code Online (Sandbox Code Playgroud)
它打印r-value。里面什么时候变成l值了deduce?
编辑1
如果我foo2在上面的代码中添加:
void foo2(int&& val)
{
static_assert(std::is_same_v<decltype(val), int&&>);
foo(val);
}
Run Code Online (Sandbox Code Playgroud)
然后从 main 调用它
foo2(1);
Run Code Online (Sandbox Code Playgroud)
l-value已打印但不r-value符合我的预期。
因此,正如评论和答案中提到的,val是 左值,因为它是一个命名变量,如果将其声明为int&&or并不重要int&。这是我以前不知道的。
use*_*522 10
每个人在介绍这一点时似乎都会感到困惑的是,值类别不是对象、变量或其他实体的属性。它不是类型或任何东西的一部分,这使得它令人困惑,因为我们还讨论左值引用和右值引用,它们是与值类别不同的概念。值类别只是单个表达式的属性。
像or这样的id 表达式,命名变量,始终是左值表达式,无论命名变量具有什么类型,无论它是引用还是局部/全局变量、函数参数或模板参数等因此,命名右值引用类型变量的表达式仍然是左值表达式。xval
表达式的第二种属性,即类型,已删除引用。因此,表达式x(or val) 的值类别是左值,其类型是,尽管名为(or )的变量int的类型是(并且没有任何值类别)。xvalint&&
像这样所选函数std::forward<T>(x)的返回类型是右值引用的函数调用表达式是 xvalue 表达式(一种右值表达式)。再说一次,表达式的类型始终是非引用的,这里是int。
有关每种表达式的值类别的完整列表,请参阅https://en.cppreference.com/w/cpp/language/value_category中的列表。