Overloads for streaming objects into std::ostream
and friends tend to only be written for lvalue ostreams.
Because it can be convenient to write code like std::ofstream("myFile.txt") << "foo";
, the standard library is specified (in [ostream.rvalue]
) to also provide the following operator<<
overload that "translates" streaming into rvalue streams to streaming into lvalue streams:
template<class Ostream, class T> // (eliding SFINAE for readability)
Ostream&& operator<<(Ostream&& os, const T& val)
{
os << val;
return std::move(os);
}
See e.g. https://github.com/microsoft/STL/blob/1a418ba4e9c373aee7e9d6ef98efa4c2e2f6b9f4/stl/inc/ostream#L996 for a proper implementation. There is also this discussion and the related LWG issue about preserving most-derived type and/or rvalueness, which have been resolved in C++20 and are not the subject of my question.
Note that the second argument is taken as const ref. I would like to understand why it was specified that way. As it stands, I could readily write an operator<<
overload for a move-only type, which will work fine with lvalue streams but fail with rvalue streams:
struct MoveOnly
{
MoveOnly() = default;
MoveOnly(const MoveOnly&) = delete;
MoveOnly(MoveOnly&&) = default;
};
template <class C, class T>
std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>&, MoveOnly x);
int main()
{
// This works fine:
std::stringstream s1{};
s1 << MoveOnly{};
// This does not compile (no suitable overload found):
std::stringstream() << MoveOnly{};
}
https://godbolt.org/z/1fexfs6Ex
Why does the standard not employ perfect forwarding here? Would there be a problem with something like:
template<class Ostream, class T> // (eliding SFINAE for readability)
Ostream&& operator<<(Ostream&& os, T&& val)
{
os << std::forward<T>(val);
return std::move(os);
}
I am writing similar code for my own stream-like class, and am wondering whether there is some disadvantage/problem I'm missing.
(The question of why this always returns the ostream instead of forwarding the inner operator<<
result is also on my mind, but the answer to that seems quite clear.)