Reputation: 7734
Is it possible to set a value more than once in a single stream such as std::cout
?
For example, the code below produces the following output.
1
0
1
1
1
This surprised me as I was expecting the output
1
0
1
0
0
As far as I can tell, when it is all concatenated in one line, the (x = false)
is ignored and it just prints x
.
#include "stdafx.h"
#include <iostream>
int main()
{
bool x;
std::cout << (x = true) << std::endl;
std::cout << (x = false) << std::endl;
std::cout << (x = true) << std::endl
<< (x = false) << std::endl;
std::cout << x << std::endl;
return 0;
}
Upvotes: 3
Views: 137
Reputation: 5710
Short answer:
You didn't specify compiler/flags, so I'd encourage you to make sure you're building for C++17 (clang/g++ flag -std=c++17
). This should fix your result, though still might cause a compilation warning. The how and why is below. Update: Unlike clang and gcc, msvc seem to be fully conformant on this one -- gives the expected result, warning-free.
Explanation: Unintuitively indeed, this unexpected result has nothing to do specifically with stream operations. It has to do with unsequenced evaluations of operands. See here in [intro.execution]:
Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a memory location is unsequenced relative to either another side effect on the same memory location or a value computation using the value of any object in the same memory location, [...] the behavior is undefined.
...
i = i++ + i; // the behavior is undefined
But behold, <<
operator (shift operators) is being noted specifically to be sequenced in the current spec (since C++17) -- see here in [expr.call]:
If an operator function is invoked using operator notation, argument evaluation is sequenced as specified for the built-in operator;
combined with this in [expr.shift]:
The value of E1 >> E2 ... The expression E1 is sequenced before the expression E2.
For your snippet, clang 6.0.1 gives this informative warning that according to these excerpts from the spec is not in conformance with the standard (!):
warning: multiple unsequenced modifications to 'x' [-Wunsequenced]
std::cout << (x = true) << std::endl
You can see it here live.
Note: This answer has been edited to reflect current state of things, thanks to user M.M who brought forth this enlightening SO link which refers to the appropriate bug reports on both clang and GCC.
Upvotes: 2
Reputation: 141628
Since C++17, the correct output for the code is 1 0 1 0 0
as you expected.
Prior to C++17, the behaviour was undefined. The C++17 standard introduced left-to-right sequencing for operands of <<
.
If the compiler doesn't give the expected output in C++17 mode (-std=c++17
) then it is a compiler bug. It has been previously noted on similar questions that the latest versions of g++ and clang++ give bogus warnings, and even in some cases incorrect behaviour in this area.
Upvotes: 3
Reputation: 10416
The misunderstanding comes from this line:
std::cout << (x = true) << std::endl
<< (x = false) << std::endl;
Before anything is printed, the two subexpressions are evaluated in an undefined order. The all assign something to x
, but the last assignment "wins" and writes the final value (in this case true) to x
. Then x
gets printed three times.
Upvotes: 0