I have the following C++ code that compiles successfully for gcc < v5.5
#include <sstream>
namespace util
{
inline void operator << (std::stringstream& stream, const char* data)
{
data = data ? data : "(null)";
std::operator<<(stream, data);
}
}
class Record
{
public:
template<typename T>
Record& operator<<(const T& data)
{
using namespace util;
m_message << data;
// std::cout << data << std::endl;
return *this;
}
private:
std::stringstream m_message;
};
int main()
{
Record r;
std::stringstream m;
r << m; //Error after gcc5.5
r << m.str(); //Ok in both
return 0;
}
Looks like passing a stringstream to a stringstream is no longer valid. I'm not sure why.
Here's a link for comparison: https://godbolt.org/z/novWE3so8
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
booldatatype.Checking if a stream is valid (e.g.
if(stream) { /*...*/ }) therefore was mandated to just return some unspecified boolean-like type:cppreference
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
Note that this allows an implicit (!) conversion from any stream to
void*.Which is unfortunate, given that
std::basic_ostreamprovides an overload for outputting pointers:cppreference
So what actually happens in your example is that the stream is implicitly converted to a
void*pointer, and thenoperator<<(const void*)is called to output that pointer.Which is probably not what you wanted to happen:
godbolt
The correct way to append a stream
C++
std::istreams can be written tostd::ostreamsby just passing the underlying stream buffer instead of the whole stream, e.g.:godbolt
So your example could be fixed like this: