This answer explains the behavior you observe with this expression:
res += (f(i), f(i + 1)), f(i + 2);
...but I would advise against using this in any production code, see the end of the answer for some reasoning.
When used in expression, the comma ,
corresponds to the comma operator which is a standard operator:
// Evaluate E1 then E2, discards the result of E1, return E2
E1, E2
The +=
operator is also an operator, with a stronger precedence than ,
(,
has the lowest precedence in C++) so:
int f();
int g();
int x = 0;
// Equivalent to:
// x += f();
// g();
x += f(), g();
// Equivalent to:
// f();
// x += g();
x += (f(), g());
In your case, you have a pair of parenthesis wrapping the two first calls:
res += (f(i), f(i + 1)), f(i + 2);
// ^--------------^
So:
f(i), f(i + 1)
is evaluated (due to the parenthesis), which result in calling f(i)
then f(i + 1)
, and storing the result of f(i + 1)
in a temporary;
- the temporary is added to
res
via the +=
operator;
- the result of
res += (f(i), f(i + 1))
is discarded;
f(i + 2)
is evaluated.
As specified in the comment, this code is equivalent to:
f(i);
res += f(i + 1);
f(i + 2);
The compiler cannot remove the call to f(i)
and f(i + 1)
because these have side effects (the update of the static
variable cnt
).
I would advise against using the comma operator for such kind of things, mainly for clarity reasons:
- You do not gain anything from this compared to the 3-lines versions except that the behavior of the one-liner is not that obvious (this question is a good example of this... ).
- Due to how the comma operator works for non built-in types, the behavior was different until C++17 for non built-in types. For instance, if
f
was returning a big_int
-like class, the order of evaluation of the operands of the operator,
was not guaranteed.
Since C++17, you get fold expressions for comma operator, which is, in my opinion, one of the very few reason to use the comma operator.