我用gcc / clang构建了这段代码并得到了不同的结果:
#include <iostream>
#include <sstream>
int main() {
std::istream& is = 1 ? std::move(std::stringstream("")) : std::cin;
}
std::stringstream("")
)初始化左值引用?没有错误
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);
^
答案 0 :(得分:6)
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
; std::stringstream
的xvalue无法转换为类型“std::istream
的左值引用”,前提条件是引用必须直接绑定到左值 - 这里没有左值来引用绑定到; std::istream
是std::stringstream
的基类,因此根据p3的第3个子弹,类型std::stringstream
的xvalue可以并且将被转换为{{1}类型的prvalue临时值通过复制初始化,它替换原始操作数以供进一步分析。std::istream
类型的prvalue,第三个操作数是std::istream
类型的左值,它们具有不同的值类别,因此p4不适用。p6中的适用项目是
第二个和第三个操作数具有相同的类型;结果是 那种类型。如果操作数具有类类型,则结果为prvalue 结果类型的临时,从任一个复制初始化 第二个操作数或第三个操作数取决于的值 第一个操作数。
所以它从转换后的第一个操作数或第二个操作数(std::istream
)复制初始化结果(这是一个prvalue临时值)。
因此错误:
std::cin
)复制初始化prvalue std::istream
结果将使用复制构造函数,并且无法复制流。std::cin
xvalue复制初始化第二个操作数的prvalue临时std::istream
是一个移动,但std::stringstream
的移动构造函数受到保护。* 对于术语(左值,左值,右值等),请参阅What are rvalues, lvalues, xvalues, glvalues, and prvalues?