I built this code with gcc/clang and got different results:
#include <iostream>
#include <sstream>
int main() {
std::istream& is = 1 ? std::move(std::stringstream("")) : std::cin;
}
std::stringstream("")
)?No error
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);
^
In the example, the main function passes an rvalue to f . The body of f treats its named parameter as an lvalue. The call from f to g binds the parameter to an lvalue reference (the first overloaded version of g ). You can cast an lvalue to an rvalue reference.
In this example, the rvalue reference a can be bound to the temporary initialized with the rvalue expression 2 , but the rvalue reference b cannot be bound to the lvalue expression i . You can bind the rvalue reference c to the temporary value 1.0 that is converted from the variable i . End of C++11 only.
To initialize the const value using constructor, we have to use the initialize list. This initializer list is used to initialize the data member of a class. The list of members, that will be initialized, will be present after the constructor after colon. members will be separated using comma.
GCC's behavior is a bug, and it's been fixed on trunk. Clang is correct. This is a messy case because you have mixed value categories for the second and third operands of the conditional operator:
std::move(std::stringstream(""))
is an xvalue* of type std::stringstream
;std::cin
is an lvalue of type std::istream
.The relevant standard quote (§5.16 [expr.cond]/p3-6) can be found in this answer. It's long enough that I don't really want to copy it over. I'll just outline how it is applied to this code:
std::istream
cannot be converted to match std::stringstream
in any way regardless of value category;std::stringstream
cannot be converted to type "lvalue reference to std::istream
" given the constraint that the reference must bind directly to an lvalue - there's no lvalue here for the reference to bind to;std::istream
is a base class of std::stringstream
, so per the 3rd bullet of p3, the xvalue of type std::stringstream
can and will be converted to a prvalue temporary of type std::istream
by copy-initialization, which replaces the original operand for further analysis.std::istream
, the third operand is an lvalue of type std::istream
, they have different value categories so p4 doesn't apply.The applicable bullet in p6 is
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.
so it copy-initializes the result (which is a prvalue temporary) from either the converted first operand, or the second operand (std::cin
).
Hence the errors:
std::istream
result from an lvalue (std::cin
) would use the copy constructor, and streams cannot be copied.std::istream
for the second operand from a std::stringstream
xvalue is a move, but std::istream
's move constructor is protected.* For terminology (lvalue, xvalue, prvalue, etc.), see What are rvalues, lvalues, xvalues, glvalues, and prvalues?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With