I'm experiencing a weird problem with stringstream
.
#include "stdafx.h"
#include "iostream"
#include "sstream"
using namespace std;
struct Test
{
float f;
};
wstringstream& operator <<( wstringstream& sstream , const Test& test )
{
sstream << test.f;
return sstream;
}
int _tmain(int argc, _TCHAR* argv[])
{
Test a;
a.f = 1.2f;
wstringstream ss;
ss << L"text" << a << endl; // error C2679!
ss << a << L"text" << endl; // it works well..
getchar();
return 0;
}
The problem is here:
ss << L"text" << a << endl; // error C2679!
ss << a << L"text" << endl; // it works well..
The only difference between these two statements is argument order. Why does the first statement fail whereas the second one works?
The problem is that ss << L"text"
gives you a std::wostream
, not a std::wstringstream
.
You only created an operator<<
for std::wstringstream
, so the next operation (which you're trying to do on a
) fails.
When you write something like
ss << L"text" << a << endl;
you are not invoking a function with four arguments.
You are, in fact, chaining multiple operations:
((ss << L"text") << a) << endl;
This works because each operator<<
operation returns a reference to the original stream object, so that you can continue chaining further operations on in this manner.
But because iostreams form an inheritance hierarchy, and because operator<<
is applicable to any output stream, the return type from your operation on wstringstream
is something a little less specific than wstringstream
.
In fact, ss << L"text"
evaluates to a wostream&
(wostream
being one of wstringstream
's base classes). The reference still refers to the same, original stream object... but it has a base class type.
So, your second operation involving a
has the following active operands:
wostream&
(on the LHS)Test
(on the RHS)But you have no wostream& operator<<(wostream&, Test const&)
. You only created a wstringstream& operator<<(wstringstream& sstream, Test const& test)
, so there's no match.
So, in fact, when creating an operator<<
for wide iostreams you should make it work for all wostream
s (clearly there is no reason to limit it to wstringstreams
):
wostream& operator<<(wostream& sstream, Test const& test)
{
sstream << test.f;
return sstream;
}
Going further, why limit yourself to wide streams? Why not normal ones too?
template<typename CharT, typename TraitsT>
std::basic_ostream<CharT, TraitsT>&
operator<<(std::basic_ostream<CharT, TraitsT>& sstream, Test const& test)
{
sstream << test.f;
return sstream;
}
Now you will be able to stream objects of your Test
class into wostream
s, ostream
s, and all their descendants, properly.