As @Rakete said in their excellent answer, this is tricky. I'd like to add on to that a little.
The ternary operator must have the form:
logical-or-expression
?
expression:
assignment-expression
So we have the following mappings:
someValue
: logical-or-expression
++x, ++y
: expression
--x, --y
or only --x
?In fact it is only --x
because an assignment expression cannot be parsed as two expressions separated by a comma (according to C++'s grammar rules), so --x, --y
cannot be treated as an assignment expression.
Which results in the ternary (conditional) expression portion to look like this:
someValue?++x,++y:--x
It may help for readability's sake to consider ++x,++y
to be computed as-if parenthesized (++x,++y)
; anything contained between ?
and :
will be sequenced after the conditional. (I'll parenthesize them for the rest of the post).
and evaluated in this order:
someValue?
(++x,++y)
or --x
(depending on bool
result of 1.)This expression is then treated as the left sub-expression to a comma operator, with the right sub-expression being --y
, like so:
(someValue?(++x,++y):--x), --y;
Which means the left side is a discarded-value expression, meaning that it is definitely evaluated, but then we evaluate the right side and return that.
So what happens when someValue
is true
?
(someValue?(++x,++y):--x)
executes and increments x
and y
to be 11
and 11
--y
, which then decrements y
back to 10
To "fix" the behavior, you can group --x, --y
with parentheses to transform it into a primary expression which is a valid entry for an assignment-expression*:
someValue?++x,++y:(--x, --y);
*It's a rather funny long chain that connects an assignment-expression back to a primary expression:
assignment-expression ---(can consist of)--> conditional-expression --> logical-or-expression --> logical-and-expression --> inclusive-or-expression --> exclusive-or-expression --> and-expression --> equality-expression --> relational-expression --> shift-expression --> additive-expression --> multiplicative-expression --> pm-expression --> cast-expression --> unary-expression --> postfix-expression --> primary-expression
Wow, that's tricky.
The compiler sees your expression as:
(someValue ? (++x, ++y) : --x), --y;
The ternary operator needs a :
, it cannot stand by itself in that context, but after it, there is no reason why the comma should belong to the false case.
Now it might make more sense why you get that output. If someValue
is true, then ++x
, ++y
and --y
get executed, which doesn't effectively change y
but adds one to x
.
If someValue
is false, then --x
and --y
are executed, decrementing them both by one.
Why would the C++ compiler generate code that for the true-branch of the ternary operator only increments
x
You misinterpreted what has happened. The true-branch increments both x
and y
. However, y
is decremented immediately after that, unconditionally.
Here is how this happens: since the conditional operator has higher precedence than comma operator in C++, the compiler parses the expression as follows:
(someValue ? ++x, ++y : --x), (--y);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^
Note the "orphaned" --y
after the comma. This is what leads to decrementing y
that has been initially incremented.
I even went as far as putting parentheses around the true-branch like this:
someValue ? (++x, ++y) : --x, --y;
You were on the right path, but you parenthesized a wrong branch: you can fix this by parenthesizing the else-branch, like this:
someValue ? ++x, ++y : (--x, --y);
Demo (prints 11 11)
Your problem is that the ternary expression doesn't really have higher precedence than comma. In fact, C++ can't be described accurately simply by precedence - and it is exactly the interaction between the ternary operator and comma where it breaks down.
a ? b++, c++ : d++
is treated as:
a ? (b++, c++) : d++
(comma behaves as if it has higher precedence). On the other hand,
a ? b++ : c++, d++
is treated as:
(a ? b++ : c++), d++
and the ternary operator is higher precedence.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With