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 resvia 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 fwas returning abig_int-like class, the order of evaluation of the operands of theoperator,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.