As far as I understand C++11 references, I should not be able to bind an rvalue reference to a (non-const) lvalue reference as the former might be bound to a temporary and the latter must never be bound to a temporary.
However I found this odd behaviour in conjunction temporary stream objects (which I reduced as far as I could)
struct Dummy {};
template <typename Stream>
Stream& operator<<(Stream& s, Dummy) {
return s << "."; // <- (A)
}
template <typename Stream>
void pass(Stream&& s) {
std::move(s) << Dummy(); // <- (X) rvalue->lvalue conversion?
}
#include <fstream>
int main() {
pass(std::fstream("test",std::ios::out));
}
If I write s << Dummy()
in line (X)
, C++ complains in line (A)
, saying
error: invalid initialization of reference of type ‘std::basic_fstream<char>&’ from expression of type ‘std::basic_ostream<char>’
However, why does the code (as shown above) compiles and works as expected? The rvalue reference returned by std::move
should just be as unable to being bound to an lvalue reference as the expression s
is, but both gcc 4.6.1
and gcc 4.7.2
react identically.
And why does this phenomenon only appear to work with streams? When directly passing a Dummy&&
to a function that expects a T&
fails both with and without std::move
.