This does not depend on the gcc version, but rather on the C++-Standard Version you're compiling for.
Your example works without problems with the latest gcc version when compiling for C++03: godbolt
The reason why this compiles at all is that pre-C++11 there was no bool
datatype.
Checking if a stream is valid (e.g. if(stream) { /*...*/ }
) therefore was mandated to just return some unspecified boolean-like type:
cppreference
operator /* unspecified-boolean-type */() const; // (until C++11)
explicit operator bool() const; // (since C++11)
Note that the conversion also was implicit pre C++11, since explicit conversion functions were added in C++11.
libstdc++ happens to define the conversion operator as follows: github
///@{
/**
* @brief The quick-and-easy status check.
*
* This allows you to write constructs such as
* <code>if (!a_stream) ...</code> and <code>while (a_stream) ...</code>
*/
#if __cplusplus >= 201103L
explicit operator bool() const { return !this->fail(); }
#else
operator void*() const { return this->fail() ? 0 : const_cast<basic_ios*>(this); }
#endif
Note that this allows an implicit (!) conversion from any stream to void*
.
Which is unfortunate, given that std::basic_ostream
provides an overload for outputting pointers:
cppreference
basic_ostream& operator<<( const void* value ); // (8)
So what actually happens in your example is that the stream is implicitly converted to a void*
pointer, and then operator<<(const void*)
is called to output that pointer.
Which is probably not what you wanted to happen:
godbolt
#include <iostream>
#include <sstream>
int main() {
std::stringstream m;
m << "foobar";
std::stringstream ss;
// equivalent to ss << static_cast<void*>(&m);
ss << m;
std::cout << ss.str() << std::endl;
// will print the address of m, e.g. 0x7ffcda4c2540
// NOT foobar!
return 0;
}
The correct way to append a stream
C++ std::istream
s can be written to std::ostreams
by just passing the underlying stream buffer instead of the whole stream, e.g.:
godbolt
#include <iostream>
#include <sstream>
int main() {
std::stringstream m;
m << "foobar";
std::stringstream ss;
ss << m.rdbuf(); // append everything from m to ss
std::cout << ss.str() << std::endl;
return 0;
}
So your example could be fixed like this:
// r << m;
r << m.rdbuf();