6
4

1 回答 1

11

basic_ostream has an overload of operator<< that looks like this:

template <typename Elem, typename Traits, typename T>
basic_ostream<Elem, Traits>&
    operator<<(basic_ostream<Elem, Traits>&& sink, const T& val)
{
    return sink << val;
}

This is called "Rvalue stream insertion" in the standard, at §27.7.3.9 [ostream.rvalue].

It allows implicit conversion (of sorts) from an rvalue basic_ostream to an lvalue. It was introduced specifically to allow temporary streams to be usable without resorting to tricks.


As for why the compile fails when you omit the move:

When Stream& operator<<(Stream& s, Dummy) is called without the move, Stream will be std::fstream which inherits from std::ostream (i.e. basic_ostream<char>).

It will use the basic_ostream<E, T>& operator<<(basic_ostream<E, T>&, const char*) overload to insert your string, then try to return the result of that expression which will be an ostream. You cannot implicitly downcast from std::ostream& to std::fstream&, so you get an error.

You can fix this by returning s on it's own line (where it won't have been implicitly upcasted.)

This isn't a problem with move because you go through that rvalue-to-lvalue insertion operator we just discovered first. Inside that function, the stream is a basic_ostream and so Stream is as well, and the return types will match.

于 2013-02-14T01:36:36.643 回答