It's been a long time since I've done any C++ programming, but I've started back up and for the most part, things are going well. This problem however, has me stumped. Basically, I'm working with the wxWidgets library which provides a class "wxString" that works like a std::string except it also provides a stream-like overloaded << operator to concatenate non-string values at the end of the string. If, for example, you have a logging function that accepts a wxString it lets you do stuff like:

However when I try to define my own overloaded << operator for my own classes, things go wrong, but ONLY if I use it on a temporary object like above. Very much condensed (and non-wxWidgets specific) here's a complete program that causes the problem:

As far as I can tell the two bits of code in the main function are functionally equivalent; so why does one give me that error?
I'm obviously missing something here and I get the feeling it's something obvious, but I can't figure out. How do I get this operator to work with temporary objects?
Thanks in advance!

StringStream() is a const StringString& -- because, as you note, it is a temporary -- and as such won't match a "plain" StreamString&.

Forgot to mention: That means that, as it stands, you have no chance of getting your function to work with a temporary object. Can you put your message in the constructor of the object instead (i.e., StringStream(ThingToPutInStringStream))?

Ah, it never occurred to me that temporaries would by definition be a bizarre kind of maybe sort of const-ish, and for some reason the compiler error didn't say anything like that either. After some more research into the whole temporaries being const business, it turns out that you are allowed to call non-const member functions on temporary objects (which is why the code in the first block in my first post did compile) but you're not allowed to pass them to functions that take non-const references. Weird. Anyway, at least I now know that this isn't a trivial problem and actually has its roots in some part of the C++ standard I don't fully understand.

Originally Posted by tabstop

Can you put your message in the constructor of the object instead (i.e., StringStream(ThingToPutInStringStream))?

Sadly, the reason I wanted to do this with an external operator is because in the real-world scenario, I'm not the one that made the "StreamString" class (i.e. wxString, which is part of the wxWidgets library), so I cannot change it in any way. My hope was to be able to provide an external operator overload in the same way you would do for std::ostream to let you easily pass your own classes to std::cout or a file stream, but it seems that if I want to go that way for wxString, I have no choice but to create a non-temporary wxString on the stack each time I want to output one of my own classes. It's not pretty, but it'll have to do. At least it works. (alternatively, I could just brute force my way past the restriction and cast a const reference to a non-const one but that seems a bit dangerous, especially with the knowledge that I don't fully understand why it has to be a const reference)

After giving it some more thought I realized that there is a way to still make this work by overloading the operator for a const left member and having that version return by value instead of reference. It's probably slower than working with references, but for non-time essential stuff that's not a problem, and it'll work without actually having to change anything in the calling code.

I actually think that declaring operator << like that makes more sense than how C++ iostreams do it. It is then consistent with how other ordinary classes would perform operator <<.
The way iostreams work, they really should have their operator<< renamed to be operator<<=, because that's what their actual behaviour is like.But hey, pretty syntax is obviously more important than consistency...

My homepage
Advice: Take only as directed - If symptoms persist, please see your debugger

Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

I actually think that declaring operator << like that makes more sense than how C++ iostreams do it. It is then consistent with how other ordinary classes would perform operator <<.
The way iostreams work, they really should have their operator<< renamed to be operator<<=, because that's what their actual behaviour is like.But hey, pretty syntax is obviously more important than consistency...

How is the stream's interpretation of the shift operators consistent with anything, whether it's << or <<=? Anyway, <<= binds right-to-left, so have fun writing this:

Code:

(((cout <<= "Hello, ") <<= name) <<= "!") <<= endl;

Also, streams are non-copyable, so having a const lhs argument simply doesn't work.

R-value references ought to improve the situation.

All the buzzt! CornedBee

"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
- Flon's Law

How is the stream's interpretation of the shift operators consistent with anything, whether it's << or <<=? Anyway, <<= binds right-to-left, so have fun writing this:

Code:

(((cout <<= "Hello, ") <<= name) <<= "!") <<= endl;

Also, streams are non-copyable, so having a const lhs argument simply doesn't work.

R-value references ought to improve the situation.

It could be consistent with regards to the constness of the arguments, if it overloaded operator<<= instead, which would make sense since it is a modifying operation. However yes, it the usage of it would be horrible.
Really, the language could have done with a separate operator for stream input e.g. <- but there's dowsides to yet another operator as well.

I'd like to clarify my statement above though, although how he has it here "makes more sense" I mean that only in terms of how the operator is defined with regards to the constness. In all practically it is not at all nice to have to return a copy, and as noted, not possible with real streams.

My homepage
Advice: Take only as directed - If symptoms persist, please see your debugger

Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"