为什么可以将rvalue间接绑定到左值引用而不是直接绑定?

eda*_*els 10 c++ c++11 c++14

从我读过和看过的内容来看,你不能将一个rvalue的表达式绑定到左值引用.然而,我所看到的是你可以将rvalue绑定到rvalue引用,并且由于命名的rvalue引用本质上是一个左值,你可以将它绑定到左值引用.禁止将右值绑定到左值引用的原因是什么.它是出于优化目的吗?

举个例子:

#include <iostream>

using std::cout;

void bar ( int& b ) {

    cout << "bar " << b << "\n";
    b = 3;
}

void foo ( int&& a ) {

    cout << a << "\n";
    bar(a);
    cout << a << "\n";
}

int main ( int argc, char ** argv ) {

    foo(1);
}
Run Code Online (Sandbox Code Playgroud)

Lig*_*ica 10

这是C++的基本规则,它可以防止错误:

int foo();

int& x = 3;      // whoops
int& y = foo();  // whoops (sometimes)
Run Code Online (Sandbox Code Playgroud)

"Rvalue references"(一组类型;不要与实际rvalues混淆)是至少部分创建的,这样如果你真的想要你仍然可以这样做:

int&& x = 3;     // oh, go on then *sigh*
int&& y = foo(); // you'd better be sure!
Run Code Online (Sandbox Code Playgroud)

在前面的示例中,我将rvalue表达式"引用"的对象绑定(或尝试绑定)到引用.

现在,我将由左值表达式命名的对象绑定到引用:

int i = foo();

int& x = i;      // no problem michael
Run Code Online (Sandbox Code Playgroud)

并确保你真的想要从左值表达式获得右值引用,引入令人难以置信的不良命名std::move:

int&& x = std::move(i);  // doesn't move anything
Run Code Online (Sandbox Code Playgroud)

这些后来的规则比原来的基本规则要晚很多,这个规则无疑阻止了过去二十年中的许多错误.

注意,Visual Studio中历来公认的T& x = bar(),其中T是一个用户定义的类型; 去搞清楚.


How*_*ant 6

禁止将右值绑定到左值参考的原因是什么?

如果没有参考Bjarne Stroustrup的宝贵而杰出的资源,C++的设计和演变,那么这个问题的答案就不可能完整.

在第3.7节中,Bjarne写道:

但是,我犯了一个严重的错误,即允许非const引用由非左值初始化.例如:

void incr(int& rr) { rr++; }

void g()
{
    double ss = 1;
    incr(ss);    // note: double passed, int expected
                 // (fixed: error in Release 2.0)
}
Run Code Online (Sandbox Code Playgroud)

由于类型的不同,int&不能引用 double传递,因此生成临时值以保存int 初始化ss的值.这样incr()修改了临时,结果没有反映回调用函数.

我强烈推荐C++的设计和演变,以便理解许多可能存在的"为什么问题",特别是关于C++ 98标准之前规定的规则.这是一个信息丰富,令人着迷的语言历史.