1

Well, I had a question about comma in ternary operator. Cut the crap, the code is below:

void test_comma_in_condition(void)
{
    int ia, ib, ic;

    ia = ib = ic = 0;
    bool condition=true;

    cout<<"Original:"<<endl;
    cout<<"ia: "<<ia<<endl;
    cout<<"ib: "<<ib<<endl;
    condition?(ia=1, ib=2):(ia=11, ib=12);
    cout<<"After:"<<endl;
    cout<<"ia: "<<ia<<endl;
    cout<<"ib: "<<ib<<endl;

    ia = ib = ic = 0;
    condition?ia=1, ib=2, ic=3:ib=22,ia=21, ic=23;
    cout<<"The operation must be bracketed, or you'll see..."<<endl;
    cout<<"ia: "<<ia<<endl;
    cout<<"ib: "<<ib<<endl;
    cout<<"ic: "<<ic<<endl;

    condition?ia=1, ib=2, ic=3:ia=21, ib=22, ic=23;
    cout<<"The operation must be bracketed, or you'll see..."<<endl;
    cout<<"ia: "<<ia<<endl;
    cout<<"ib: "<<ib<<endl;
    cout<<"ic: "<<ic<<endl; 

    return;
}

The output will be like:

Original:
ia: 0
ib: 0
After:
ia: 1
ib: 2
The operation must be bracketed, or you'll see...
ia: 21
ib: 2
ic: 23
The operation must be bracketed, or you'll see...
ia: 1
ib: 22
ic: 23

Is this legal?

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
Joseph
  • 51
  • 1
  • 3
  • 2
    You're saying `a ? b : c, d` should mean `a ? b : (c, d)` instead of `(a ? b : c), d`. Without getting into the question of which is correct, what is your reason for doubting the compiler? –  Feb 08 '12 at 08:02
  • 4
    Yes it is legal - but also unreadable. – Ed Heal Feb 08 '12 at 08:04

4 Answers4

8

This is a matter of operator precedence. Your expression:

condition?ia=1, ib=2, ic=3:ib=22,ia=21, ic=23;

is understood by the compiler as:

(condition?(ia=1, ib=2, ic=3):(ib=22)),ia=21, ic=23;

At this point you should be able to see why you get the program output.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • 1
    Playing devil's advocate, but if this is a matter of precedence why does `,` appear to have higher precedence than `?:` in the "middle" of the conditional expression but lower precedence in tail of the conditional expression? – CB Bailey Feb 08 '12 at 08:22
  • I +1'd your answer because it answered this good question - comma expressions are part of `expression` but not of `assignment-expression`. – Greg Hewgill Feb 08 '12 at 08:26
  • 1
    You can't really invoke precedence here. Formally, C++ operators aren't ordered by precedence, but by different productions in the grammar. Most of the time, the effect is the same as if there were a precedence corresponding to the order the productions are presented in the standard, but there are at least two exceptions: here (where the second term can be _any_ expression), and in some cases involving C style casts and prefix operators. – James Kanze Feb 08 '12 at 08:30
  • @JamesKanze If an almost-C++-but-not-quite language worked with precedence and used it to resolve ambiguities in the grammar, this isn't an example where the behaviour would differ, because the expression `a ? b, c : d` wouldn't be ambiguous in the first place. –  Feb 08 '12 at 09:25
  • @hvd If C++ was defined using precedence, either `a ? b : c, d` would group `a ? b : (c, d)` or `a ? b , c : d` would be illegal. – James Kanze Feb 08 '12 at 10:41
  • @JamesKanze In that fictional language, if `,` has lower precedence than `?:`, `a ? b , c : d` would still be valid because the grammar defines exactly one possible parse. Precedence is ignored, because precedence is used only when the grammar allows multiple parses. –  Feb 08 '12 at 10:55
  • @JamesKanze Wait, I think I see why we draw different conclusions... Your hypothetical language has binary `?` and `:` operators? If so, you're right. In my hypothetical language, `?:` is still a ternary operator. –  Feb 08 '12 at 11:19
6

Yes, the relevant grammar for a conditional expression is:

logical-or-expression ? expression : assignment-expression

for assignment expressions (which can also be a conditional-expression or a throw-expression):

logical-or-expression assignment-operator assignment-expression

and for an expression with a comma operator (an assignment-expression can also be an expression):

expression , assignment-expression

This means that the construct a ? b : c, d cannot be parsed as equivalent to a ? b : (c, d) because c, d is not an assignment-expression but must be parsed as equivalent to (a ? b : c), d.

There is no undefined behaviour in condition ? ia=1,ib=2,ic=3 : ia=21, ib=22, ic=23; because evaluation of condition is sequenced before the evaluation of either the second or third operands of ?: and in every sub-expression containing a comma operator the evaluation of the first operand of the comma operator is sequenced before the evaluation of the second operand.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
3

It's legal, but stupid not very useful to write code like that.

The code

condition?ia=1, ib=2, ic=3:ia=21, ib=22, ic=23;

is equivalent to

condition?(ia=1, ib=2, ic=3):ia=21;
ib=22;
ic=23;

just harder to read.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • Another question? How does the comma parsed here? Or how the comma is used? – Joseph Feb 16 '12 at 01:20
  • The comma operator can be used to separate expressions, like it does here. Unlike the semicolon, which *terminates* the expression, the comma allows you to have several expressions in a place that would otherwise only allow one. Not very useful in practice, and likely to cause confusion to the reader. – Bo Persson Feb 16 '12 at 06:38
1

The problem is that the comma operator has the lowest precedence there is. Thanks to that, the else part of the conditional operator is just the first assignment, after that the comma operator kicks in and the other two statements will be executed just aswell.

Xeo
  • 129,499
  • 52
  • 291
  • 397