以下C++ 11代码无法编译:
struct T {};
void f(T&&) { }
void g(T&& t) { f(t); }
int main()
{
g(T());
}
Run Code Online (Sandbox Code Playgroud)
正确的方法是:
void g(T&& t) { f(move(t)); }
Run Code Online (Sandbox Code Playgroud)
这很难用正确的自然语言术语来解释.该参数t似乎失去了它需要恢复的"&&"状态std::move.
你叫什么的T()在g(T())?
你叫什么的T&&在g(T&& t)?
你叫什么的t在g(T&& t)?
你叫什么的t在f(t)和f(move(t))?
你怎么称呼返回值move(t)?
你怎么称呼整体效果?
该标准的哪个部分处理此问题?
所有参数都是左值,即使它们的类型是"右值参考".它们有名称,因此您可以根据需要随时查看它们.如果命名的右值引用是rvalues,那么你会得到令人惊讶的行为.我们不希望从左值的隐式移动,这就是你必须明确写的原因std::move.
关键点在于参数T&& b只能绑定到右值,但是稍后引用时表达式b是左值.
所以函数的参数必须是一个rvalue,但是在函数体内,参数是一个左值,因为那时你已经绑定了一个引用并给它一个名字,它不再是一个未命名的临时值.
表达式具有类型(例如int,string等等)并且它具有值类别(例如,左值或右值),并且这两个事物是不同的.
一个命名变量,声明为T&& b具有"rvalue reference to T" 类型,并且只能绑定到rvalue,但是当您稍后使用该引用时,该表达式b具有值类别"lvalue",因为它具有名称并引用某个对象(无论引用是什么,即使这是一个右值.)这意味着传递b给另一个带rvalue的函数,你不能只说f(b)因为b是左值,所以你必须将它(后)转换为rvalue,通过std::move(b).
你在g(T())中称之为T()?
临时的(可移动的).
你怎么称待T && in g(T && t)?
T &&是一个r值引用,表示可以移动的对象.
你怎么称呼t(g&t)?
t实际上是一个l值,因为你可以通过名字来引用它.
你在f(t)和f(move(t))中称为t?
你怎么称为move(t)的返回值?
r值参考
作为一个笔记; 你应该调用结构C,并写一个单独的例子,其中T实际上是寺庙化的.该代码需要不同的话,因为在一个函数template< typename T > void f( T&& t );,你不能简单地使用std::move()而不被非常小心,因为T实际上可以是一个const&,在这种情况下,你不能使用std::move(),而是使用完美转发与std::forward< T >( t )