在c++ 11中将非const左值引用绑定到右值是否有效?(修改)

Is it valid to bind non-const lvalue-references to rvalues in C++ 11?(modified)

本文关键字:是否 有效 修改 绑定 引用 c++ const      更新时间:2023-10-16

我知道在c++03中,一个非const引用不能绑定到右值。

T& t = getT();是无效的,在c++11中,我们可以这样做:T&& t = getT();,但是上面的代码呢,应该在c++11中工作吗?

我用vs11测试了下面的代码:

 Foo getFoo() {
  return Foo();
}
void fz(Foo& f) {
}
int getInt() {
  return int();
}
void iz(int& i) {
}
int main() {
  {
    Foo& z = getFoo(); //ok
    fz(getFoo()); //ok
    int& z2 = getInt(); //error: initial value of reference to non-const must be an lvalue
    iz(getInt()); //same as above
  }
}

Foo是一个自定义类,我不明白为什么前两行编译。z的临时引用在main的内部作用域结束时被销毁。标准对此有什么规定吗?

class Foo {
public:
  Foo() {
    std::cout << "constructedn";
  }
  ~Foo() {
    std::cout << "destructedn";
  }
};

我刚刚看到一个类似的问题:一个VS2010 bug ?允许绑定非const引用到右值,甚至没有警告?

应该在c++11中工作吗?

不,它不应该。

Foo是一个自定义类,我不明白为什么前两行编译

只能用MSVC编译。MSVC有一个(很有用的)编译器扩展,它允许将用户定义类型的左值绑定到右值,但是标准本身禁止这样做。请看下面的例子,GCC 4.7.2拒绝编译你的代码。

标准对此有规定吗?

确实如此。c++ 11标准第8.5.3/5段:

对类型"cv1 T1"的引用由类型"cv2 T2"的表达式初始化,如下所示:

—如果引用是左值引用,且初始化表达式

-是左值(但不是位域)," cv1 T1 "与" cv2 T2 "或

是引用兼容的

-有一个类类型(即T2是一个类类型),其中T1T2不是引用相关的,但可以是隐式转换为类型为" cv3 T3 "的左值,其中" cv1 T1 "与" cv3 T3 "引用兼容[…],

则在第一种情况下,引用被绑定到初始化表达式lvalue和lvalue结果的转换(或在任何一种情况下,转换为适当的基类子对象)对象)。[…]

[…]

- 否则,该引用必须是对非易失性const类型的左值引用(即cv1必须是)const),或者引用必须是右值引用。(例子:

double& rd2 = 2.0; // error: not an lvalue and reference not const
int i = 2;
double& rd3 = i; // error: type mismatch and reference not const

-end example]

不能将临时类型绑定到非const左值引用。

T f();
T& t1 = f(); // won't compile
const T& t2 = f(); // OK
T&& t3 = f(); // OK

这是一个安全功能。用一个无论如何都要死亡的左值来改变临时变量很可能是一个逻辑错误,因此语言是不允许的。

注意,由于RVO比在实践中:

T&& t3 = f();

T t3 = f();
相当于