One nasty thing about redirection operators <<
is that they intuitively convey an indea of "sequential computation" that indeed is not present.
When you write
std::cout << f() << g() << std::endl;
the output will show first the result of f()
and then the result of g()
, but the actual call to g()
may happen before the call to f()
.
It even gets worse than this... it's not that the sequence is not predictable, but that indeed the very concept of sequence is not valid. In
std::cout << f(g()) << h(i()) << std::endl;
it's for example legal that the first function being called is g()
, followed by i()
, followed by h()
and finally by f()
. It's not even guaranteed that order will be the same for all invocations (not because compiler makers likes to make fun of you, but because the code can be inlined and the compiler may decide a different order if the containing function is inlined in a different context).
The only C++ operators that guarantee a sequence in the evaluation order are:
&&
: first evaluates left side and only if the result is "true" evaluates the right side
||
: first evaluates left side and only if the result is "false" evaluates the right side
?:
: evaluates first the condition and then only the second or the third operand
,
: the comma operator... evaluates the left side, drops the value and then evaluates and returns the right side. NOTE: the commas between function parameters are NOT comma operators and no evaluation order is imposed.
Moreover this guaratee is valid only for the predefined operators. If you overload &&
, ||
or ,
in your class they're just normal operators without any special restrictions on evaluation order.
Any other operator doesn't impose any restriction on the evaluation order, and this includes <<
even if the usage sort of tricks you into thinking that.