10

What's happening here?

#include <iostream>
using namespace std;

int main(){

    int x=0,y=0;
    true? ++x, ++y : --x, --y; 
    cout << "x: " << x << endl;
    cout << "y: " << y << endl; //why does y=0 here?

    x=0,y=0;
    false ? ++x, ++y : --x, --y; 
    cout << "x: " << x << endl;
    cout << "y: " << y << endl;
}

x: 1
y: 0

x: -1
y: -1

The second case seems fine. I would expect both x and y to increment to 1 in the first case but only the left hand operand increments.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
hhbilly
  • 1,265
  • 10
  • 18

3 Answers3

20

The first one is equivalent to:

(true  ? (++x, ++y) : (--x)), --y; 

The second one is equivalent to:

(false ? (++x, ++y) : (--x)), --y; 

Thus the --y is always executed. In the first line, the increments are executed first so x = 1, y = 0 is expected. In the second line, the decrement of x is executed first so x = -1, y = -1 is expected.


As noted in a comment (to another answer) by Barmar:

And in case anyone is wondering why the comma between ++x and ++y doesn't have the same effect, it's because (true? ++x) would not be valid at all. So the compiler keeps scanning until it finds the :, but beyond that it stops when it reaches a lower precedence operator [(, in this example) or the end of statement].

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    To state your final paragraph more precisely: precedence (and associativity) of operators only affects binding of the operands at the left and right of the operator, not the one in the middle. Of course the ternary operator is the only one to have a middle operand at all in the first place. But along these lines one might consider a pair of parentheses as a unary (identity) operator whose single operand is in the middle (between the "operator symbols"), which would explain why the grouping it achieves is unaffected by any precedence rules. – Marc van Leeuwen Apr 18 '14 at 14:02
4

The y is zero because comma has the lowest precedence among all C++ operators. Because its precedence is lower than that of the ternary conditional operator, the conditional operators are parsed as true? ++x, ++y : --x and false? ++x, ++y : --x. In both cases, the --y statement is executed unconditionally.

EDIT The first comma is different because the compiler has found a ?, so now it needs a : to complete the "when true" expression of the conditional. That is why both ++x and ++y are taken in.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 4
    And in case anyone is wondering why the comma between `++x` and `++y` doesn't have the same effect, it's because `(true? ++x)` would not be valid at all. So it keeps scanning until it finds the `:`, but beyond that it stops when it reaches a lower precedence operator. – Barmar Aug 27 '12 at 04:27
  • 1
    Oh and never do `if(x==100,000)` learnt that the hard way ;-) – Adrian Cornish Aug 27 '12 at 04:30
0

Read the standard

§5.18 Comma operator [expr.comma]

¶1 The comma operator groups left-to-right.

expression:
assignment-expression
expression , assignment-expression

A pair of expressions separated by a comma is evaluated left-to-right; the left expression is a discardedvalue expression (Clause 5).83 Every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression. The type and value of the result are the type and value of the right operand; the result is of the same value category as its right operand, and is a bit-field if its right operand is a glvalue and a bit-field.

¶2 In contexts where comma is given a special meaning, [ Example: in lists of arguments to functions (5.2.2) and lists of initializers (8.5) —end example ] the comma operator as described in Clause 5 can appear only in parentheses. [ Example:

f(a, (t=3, t+2), c);

has three arguments, the second of which has the value 5. —end example ]

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Adrian Cornish
  • 23,227
  • 13
  • 61
  • 77
  • Thanks. true? (++x, ++y) : (--x, --y); fixed. Lesson: always use parenthesis where intent is non trivial. – hhbilly Aug 27 '12 at 04:46
  • 2
    @user1626720 - not to mention "don't abuse the ternary operator". The code in question should be written with if ... else, since the value of the ternary operator is discarded. – Pete Becker Aug 27 '12 at 11:56