Re: operator << for ostringstream returning ostream is unintuitive
Is it not a reasonable user assumtion that the return type of <<
should be the same the type as its first argument?
No, it's not a reasonable assumption. I often use ostream types that
take some set-up action before doing output, then return a temporary
object whose destructor will do some tear-down. For example, I'm fond
of a logging stream that prints a date-stamp before the inserted value,
then returns a temporary stream whose destructor will print a newline:
log << "received packet with id " << packet1.id();
log << "received packet with id " << packet2.id();
I still think one should try and return a operators first argument as
its full type when chaining, if possible. Users expect operators
(overloaded or not) to behave much like they do for the built in
types. So if we take the advice of "if in doubt, do as the ints do".
Then because typeid(int) == typeid(int(1) << long(1)), then maybe
also typeid(ostringstream()) == typeid(ostringtream() << long(1))
should hold. It doesnt, but I dont think it would hurt to make it
hold.
When it comes to your prefix postfix stream wrappers.. I assume it
looks something like this:
struct Log {
Log(std::ostream & os): os_(os) {
os_ << " (prefix) ";
}
template <typename T>
LogPostfix operator << (const T& t) {
os_ << t;
return LogPostfix(os_);
}
private:
std::ostream &os_;
};
void func(Log& log) {
log << "Testing";
}
int main(void) {
Log(std::cout) << "Test1"; //OK
Log(std::cout) << "Test" << 2; //OK
Log log(std::cout);
log << "Test" << 3; // OK
Log(std::cout) << "Test" << 4; //OK
func(Log(std::cout)); //OK
func(Log(std::cout) << "Test6"); //ERROR
for(;;);
}
//outputs:
// (prefix) Test1 (postfix)
// (prefix) Test2 (postfix)
// (prefix) Test3 (postfix)
// (prefix) Test4 (postfix)
// (prefix) Testing (postfix)
I see that operator << for Log has to return a different type than the
type of the implicit first argument *this. I think thats probably Okay
in this example because the LogPostfix that is returned instead of
Log& does not differ from the public interface of the former. So no
syntax is lost to the user in the internal switch of the type of
streams. Here it takes a little more effort to break the users
illusion that there is just one type of stream (by passing the
temporary internal stream type to a function that expects the regular
stream type).
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]