我用 gcc/clang 构建了这段代码并得到了不同的结果:
#include <iostream>
#include <sstream>
int main() {
std::istream& is = 1 ? std::move(std::stringstream("")) : std::cin;
}
- 为什么 gcc 允许用右值初始化左值引用 (
std::stringstream("")
)? - 为什么 clang 会尝试调用复制构造函数?
海湾合作委员会4.9.1
没有错误
clang 3.4
prog.cc:5:63: error: call to implicitly-deleted copy constructor of 'istream' (aka 'basic_istream<char>')
std::istream& is = 1 ? std::move(std::stringstream("")) : std::cin;
^~~~~~~~
/usr/local/libcxx-3.4/include/c++/v1/istream:185:5: note: copy constructor is implicitly deleted because 'basic_istream<char, std::__1::char_traits<char> >' has a user-declared move constructor
basic_istream(basic_istream&& __rhs);
^
prog.cc:5:28: error: calling a protected constructor of class 'std::__1::basic_istream<char, std::__1::char_traits<char> >'
std::istream& is = 1 ? std::move(std::stringstream("")) : std::cin;
^
/usr/local/libcxx-3.4/include/c++/v1/istream:185:5: note: declared protected here
basic_istream(basic_istream&& __rhs);
^
prog.cc:5:28: error: calling a protected constructor of class 'std::__1::basic_istream<char, std::__1::char_traits<char> >'
std::istream& is = 1 ? std::move(std::stringstream("")) : std::cin;
^
/usr/local/libcxx-3.4/include/c++/v1/istream:185:5: note: declared protected here
basic_istream(basic_istream&& __rhs);
^
最佳答案
GCC 的行为是一个错误,它是 been fixed on trunk .铛是正确的。这是一个困惑的情况,因为条件运算符的第二个和第三个操作数具有混合值类别:
std::move(std::stringstream(""))
是std::stringstream
类型的 xvalue*;std::cin
是std::istream
类型的左值。
相关标准报价(§5.16 [expr.cond]/p3-6)可以在this answer中找到.够长了,我真的不想复制过来。我将概述它是如何应用于此代码的:
- 显然
std::istream
无法以任何方式转换以匹配std::stringstream
,无论值类别如何; - 鉴于引用必须直接绑定(bind)到左值 - 这里没有左值供引用绑定(bind);
std::istream
是std::stringstream
的基类,因此根据 p3 的第 3 个项目符号,std::stringstream 类型的 xvalue
可以并且将通过复制初始化转换为std::istream
类型的临时纯右值,它替换原始操作数以供进一步分析。- 现在第二个操作数是
std::istream
类型的纯右值,第三个操作数是std::istream
类型的左值,它们有不同的值类别所以p4 不适用。 - 因此结果是每个 p5 的纯右值。由于它们具有相同的类型,因此不执行 p5 中指定的重载决策,您继续执行 p6。
p6中适用的项目符号是
The second and third operands have the same type; the result is of that type. If the operands have class type, the result is a prvalue temporary of the result type, which is copy-initialized from either the second operand or the third operand depending on the value of the first operand.
因此它从转换后的第一个操作数或第二个操作数 (
std::cin
) 复制初始化结果(临时纯右值)。
因此出现错误:
- 从左值 (
std::cin
) 复制初始化右值std::istream
结果将使用复制构造函数,并且无法复制流。< - 为
std::stringstream
的第二个操作数复制初始化右值临时std::istream
xvalue 是一个移动,但是std::istream
的移动构造函数受到保护。
* 有关术语(左值、xvalue、prvalue 等),请参阅 What are rvalues, lvalues, xvalues, glvalues, and prvalues?
关于c++ - 用右值初始化左值引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27879704/