了解右值参考

mos*_*ald 16 c++ rvalue-reference c++11

我认为我对rvalue引用并不十分了解.为什么以下错误无法编译(VS2012)'foo' : cannot convert parameter 1 from 'int' to 'int &&'

void foo(int &&) {}
void bar(int &&x) { foo(x); };
Run Code Online (Sandbox Code Playgroud)

我会假设int &&从bar传递到foo时将保留该类型.为什么它会int在函数体内转换成一次?

我知道答案是使用std::forward:

void bar(int &&x) { foo(std::forward<int>(x)); }
Run Code Online (Sandbox Code Playgroud)

所以也许我只是没有清楚地掌握原因.(另外,为什么不std::move呢?)

Sau*_*ack 13

我总是记得左值作为一个有名字或可以解决的值.由于x具有名称,因此它将作为左值传递.引用rvalue的目的是允许函数以它认为合适的任何方式完全破坏值.如果我们在您的示例中通过引用传递x,那么我们无法知道执行此操作是否安全:

void foo(int &&) {}
void bar(int &&x) { 
    foo(x); 
    x.DoSomething();   // what could x be?
};
Run Code Online (Sandbox Code Playgroud)

这样做foo(std::move(x));是明确地告诉编译器你已完成x并且不再需要它.如果没有这一举动,现有代码就会发生不好的事情.这std::move是一种保障.

std::forward 用于模板中的完美转发.


Mik*_*our 11

为什么它会int在函数体内转换成一次?

它没有; 它仍然是对rvalue的引用.

当一个名字出现在表达式中时,它就是一个左值 - 即使它恰好是对右值的引用.如果表达式要求(即如果需要它的值),它可以转换为值; 但它不能绑定到右值参考.

正如您所说,为了将其绑定到另一个右值引用,您必须将其显式转换为未命名的右值.std::forward并且std::move是方便的方法.

另外,为什么不std::move呢?

为什么不呢?这比std::forward那些不知道参数是否是引用的模板更有意义.


Dav*_*rtz 9

这是" 无名称规则 ".里面bar,x有一个名字...... x.所以它现在是一个左值.将某些东西作为右值引用传递给函数并不会使它成为函数内的右值.

如果你不明白为什么必须这样,那就问问自己 - 回归x之后是什么foo?(记住,foo可以随意移动x.)