14

The comma operator guarantees left-to-right evaluation order.

[n3290: 5.18/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 discarded value expression (Clause 5). 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.

The only other clause regarding the operator doesn't mention evaluation order. So it would appear that this is still the case when the operator has been overloaded.

But then, further up, in the general spiel regarding expressions, of course it is stated that the rules change when you overload operators:

[n3290: 5/2]: [ Note: Operators can be overloaded, that is, given meaning when applied to expressions of class type (Clause 9) or enumeration type (7.2). Uses of overloaded operators are transformed into function calls as described in 13.5. Overloaded operators obey the rules for syntax specified in Clause 5, but the requirements of operand type, value category, and evaluation order are replaced by the rules for function call. Relations between operators, such as ++a meaning a+=1, are not guaranteed for overloaded operators (13.5), and are not guaranteed for operands of type bool. —end note ]

However, this is non-normative text. Is there any normative text defining this rule, or could a compliant compiler ignore it?

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 2
    In my mind, and according to [Wikipedia](http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Other_operators), if the comma operator is overloaded it is simply replaced with a function call, and isn't the evaluation order of function call arguments implementation dependent? Which of course means that the right side may be evaluated first? – Some programmer dude Oct 19 '11 at 12:02
  • 1
    @JoachimPileborg: Yes, but the question is, which normative passage in the standard specifies this? Neither your mind nor Wikipedia are authoritative, and you only stated what I already did. ;) – Lightness Races in Orbit Oct 19 '11 at 12:06
  • Ah, sorry. I should stop reading advanced questions right after lunch! :) – Some programmer dude Oct 19 '11 at 12:08
  • 1
    @JoachimPileborg: Lunch... now there's a good idea! – Lightness Races in Orbit Oct 19 '11 at 12:10
  • 1
    Am I the only one who scratches my head wondering why the comma operator can be overloaded in the first place (rather than specifying that it always returns the type of the right hand operand)? Or, for that matter, wonders why the overloads "&&" and "||" are overloaded with a single function rather than a set of them used something like : "a && b" becomes "fn2(temp = fn1(a)) ? fn3(temp) : fn4(temp, b))", where the first parameter of fn2-fn4 must match the return type of fn1, and the needed compiler-temp variable would be auto-declared that type? – supercat Nov 04 '11 at 21:16
  • @supercat: I don't really understand your example (it's late here), but your question as to why `op,` can be overloaded is certainly not a strange one :) – Lightness Races in Orbit Nov 05 '11 at 01:49
  • The big thing about "," is that it is in a real sense more of a "syntax element" than an operator per se (especially since it ignores the left-hand operand entirely). With regard to "&&" and "||", I can certainly see uses for overloads, but the fact that the right-hand operand is only evaluated conditionally is a crucial aspect of their operation. I'm not sure the best way to incorporate that into the language. Perhaps ideal would be to have a 'lazy evaluate' kind of parameter, and an "evaluate" statement. An attempt to use the parameter before evaluating it, or to evaluate... – supercat Nov 19 '11 at 18:33
  • ...the same parameter more than once, would be Undefined Behavior. Actually, thinking about that approach, I like it. If a function with such a parameter were called as an ordinary function (rather than being compiled in-line) the parameter would be passed as a code address, and a local variable would be allocated to hold its post-evaluation value. The code address wouldn't be for an ordinary "callable" function, though; it could be for a piece of code which accepted the old frame pointer in a register and could use the earlier function's execution context. – supercat Nov 19 '11 at 18:36
  • Thus, the overhead of such a parameter with an "ordinary" function call would be pretty reasonable (a push, a computed call, and a return). In-line functions, of course, could simply include the evaluation code at the appropriate spot within the in-line function. The more I think about the idea, the more I like it. Too bad there's no way to have a little birdie whisper it in the ears of the C++ gods. – supercat Nov 19 '11 at 18:38
  • @supercat: I stopped reading at "since it ignores the left-hand operand entirely", since that's "entirely" and completely wrong. – Lightness Races in Orbit Nov 20 '11 at 01:42
  • @Tomalak Geret'kal : Sorry, I should have said "generally ignores *the value of* the left-hand operand entirely". The left-hand operand is, of course, evaluated for side-effects. I'm not sure of the semantics in the case where the left-hand operand would be a throw expression, but I can't think of any other case where the value of the left-hand operand would not be entirely ignored. Am I missing any? – supercat Nov 20 '11 at 19:08
  • @TomalakGeret'kal: In any case, I would suggest that the fact that the comma, double-ampersand, and double-pipe operators have specific defined sequence-point behavior when their operands are "normal" types would suggest that such behaviors should be considered an essential aspect of how the operators work; while it may be useful to have overrides especially for the latter two operators, such overrides should be able to retain the semantics of the original operators. – supercat Nov 20 '11 at 19:12
  • @supercat: I guess I still don't know what you're trying to say! – Lightness Races in Orbit Nov 20 '11 at 19:12
  • @TomalakGeret'kal: Basically that since comma, double-ampersand, and double-pipe have semantics which are completely different from a function call, it seems odd to allow them to be overloaded in such a way as to replace them with a function call, but not in a way that allows them to be overloaded and yet maintain the special aspects of their semantics. I then suggested a hypothetical enhancement to C++ could, for reasonable runtime cost, allow functions to provide such semantics by controlling when and whether their arguments are evaluated. – supercat Nov 20 '11 at 19:56
  • @supercat: Why _runtime_ cost? – Lightness Races in Orbit Nov 20 '11 at 20:16
  • @TomalakGeret'kal: If conditionally-evaluated arguments were restricted to functions expanded in-line, there wouldn't have to be any runtime costs, but I don't think compilers are required to actually in-line any functions at all. Suppose a non-inline function was supposed to behave like the double-ampersand operator. The caller of such a function couldn't evaluate the second argument before calling the function, but would have to allow the function to request the evaluation of that argument during its execution. The most efficient mechanism I can figure would be a callback. – supercat Nov 20 '11 at 20:52

1 Answers1

10

I only have the 03 standard to hand, but in it 5/3 says "Clause 5 defines the effects of operators when applied to types for which they have not been overloaded."

So all of clause 5, including 5.18/1, only applies to the built-in operators and not to any overloaded function.

(A compliant compiler could always evaluate the operands to an overloaded operator ,() left to right though.)

Alan Stokes
  • 18,815
  • 3
  • 45
  • 64
  • Oh, so it does (`5/3`). Good spot! – Lightness Races in Orbit Oct 19 '11 at 12:07
  • Hmm, this would also mean ordering for `+ - / *` is not specified when overloaded. That seems wrong... – edA-qa mort-ora-y Oct 19 '11 at 12:23
  • 1
    @edA-qamort-ora-y: the ordering for most operators is not specified, whether or not they are overloaded. Only built-in `, && || ?:` introduce sequence points. – Mike Seymour Oct 19 '11 at 12:34
  • 2
    @MikeSeymour: In C++11, they don't induce "sequence points" any more :-) – Kerrek SB Oct 19 '11 at 12:45
  • 1
    @edA: You're thinking inter-prescedential. `* /` still have a higher prescedence than `+ -`. It's just that multiple `operator,` all got the same prescedence. Also, this question was about the order of evaluation of the arguments, not directly about the order of operator calls. – Xeo Oct 19 '11 at 12:48
  • @Xeo,Mike, my concern is that the precedence of operators is also defined in Clause 5. That is, the clause Alan says discards the evaluation order for the comma operator would also appear to discard the precedence rules for overloaded operators. Unless there is some other clause saying it doesn't. – edA-qa mort-ora-y Oct 19 '11 at 14:01
  • 3
    @edA: Precedence and evaluation order are two separate things; the former is about how the tokens in your code are parsed lexically to form a syntax tree in the compiler, and the latter is about in which order those tokens are actually evaluated at runtime. – Lightness Races in Orbit Oct 19 '11 at 15:34
  • @TomalakGeret'kal, I understand that logically, but please look at Clause 5. This is where precedence is defined according to the syntax tree, as is evaluation order. Alan's snippet indicates all of Clause 5 is subject only to built-operators and not overloaded ones. I agree the syntax tree should remain intact, but I don't see in the wording that this is the case. – edA-qa mort-ora-y Oct 19 '11 at 15:38
  • 2
    @edA-qamort-ora-y 5/2 says "Overloaded operators obey the rules for syntax specified in clause 5". – Alan Stokes Oct 19 '11 at 16:01
  • @Alan, _(replacing my obviously broken glasses)_, indeed, thanks. – edA-qa mort-ora-y Oct 19 '11 at 16:07
  • @edA-qamort-ora-y: Oh, I see. :) – Lightness Races in Orbit Oct 19 '11 at 16:58