在 C++ 中,将右值隐式转换为左值引用是非法的。考虑以下代码,其中左值引用绑定到右值(lambda):
int main()
{
auto& f = []() -> void {};
return 0;
}
gcc (4.8.1) 不接受这样的代码(非常有意义)。但是,Microsoft 编译器确实接受它,这意味着它要么接受非标准代码,要么 C++ 允许将左值引用绑定到右值 lambda 表达式的特殊情况。
问题:哪个假设是正确的?
在 C++ 中,将右值隐式转换为左值引用是非法的。考虑以下代码,其中左值引用绑定到右值(lambda):
int main()
{
auto& f = []() -> void {};
return 0;
}
gcc (4.8.1) 不接受这样的代码(非常有意义)。但是,Microsoft 编译器确实接受它,这意味着它要么接受非标准代码,要么 C++ 允许将左值引用绑定到右值 lambda 表达式的特殊情况。
问题:哪个假设是正确的?
The core of your question is: can rvalues be bound to non-const lvalue references?
The Standard says no. rvalues can only be bound to const lvalue references.
I believe the relevant Standard paragraph is 8.5.3/5:
A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:
...
- Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1 shall be const), or the reference shall be an rvalue reference.
However Microsoft has a long-standing "feature" that allows this non-standard behaviour, which explains what you're witnessing.
引用Herb Sutter(ISO C++ 标准委员会主席)的话:
一个符合标准的 C++ 编译器总是可以允许非法的 C++ 代码编译并赋予它一些意义——嘿,如果一些古怪的编译器编写者愿意实现那个扩展,它可以选择允许内联 COBOL,也许是在喝了太多龙舌兰酒之后。对于某些类型的扩展,C++ 标准要求编译器至少发出一些诊断信息,说明代码不是有效的 ISO C++,就像这个编译器一样。
他进一步解释了以下示例如何非法:
// Example 2
string f() { return "abc"; }
void g() {
string& s = f(); // illegal?
cout << s << endl;
}
请访问 Sutter 的此链接以获得解释,以避免重复有关 SO 的文章。
但是,Microsoft 编译器确实接受它,这意味着它要么接受非标准代码,要么 C++ 允许将左值引用绑定到右值 lambda 表达式的特殊情况。
MSVC 以拥有这个(不是很好)编译器扩展而闻名。它只是允许将右值绑定到对非的左值引用const
:
A& x = A(); // Illegal in C++, allowed by MSVC