I would advice against using such "tricks" in your code in the long term this is maintenance nightmare and is hard to reason about. There are almost always alternatives, for example this code:
testStruct test = {a[++i], b[i]}
could be changed to:
++i ;
testStruct test = {a[i], b[i]}
So having said that, neither case uses the comma operator in both functions calls and intialization lists the comma is a grammar elements and nothing else.
Your first situation is well defined although there is some caveats depending on whether this is C++11 or pre C++11.
In both cases there is a sequence point after each comma, although pre C++11 the order of evaluation is not specified. So we can see this for the pre C++11 case by going to defect report 430 which says:
A recent GCC bug report (
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11633) asks about the
validity of
int count = 23; int foo[] = { count++, count++, count++ };
is this undefined or unspecified or something else?
and the answer is (emphasis mine going forward):
I believe the standard is clear that each initializer expression in
the above is a full-expression (1.9 [intro.execution]/12-13; see also
issue 392) and therefore there is a sequence point after each
expression (1.9 [intro.execution]/16). I agree that the standard does
not seem to dictate the order in which the expressions are evaluated,
and perhaps it should. Does anyone know of a compiler that would not
evaluate the expressions left to right?
In C++11 it is baked in the draft C++11 standard in section 8.4.5
paragraph which says:
Within the initializer-list of a braced-init-list, the
initializer-clauses, including any that result from pack expansions
(14.5.3), are evaluated in the order in which they appear. That is,
every value computation and side effect associated with a given
initializer-clause is sequenced before every value computation and
side effect associated with any initializer-clause that follows it in
the comma-separated list of the initializer-list.
I am sticking with C++11 going forward since it does not change the answer for the rest of the content, although the wording on sequencing does vary the conclusion is the same.
The second situation invokes undefined behavior since the order of evaluation of arguments to a function are unspecified and their evaluation is indeterminately sequenced with respect to one another. We can see this undefined behavior from section 1.9
paragraph 15 which says:
Except where noted, evaluations of operands of individual operators
and of subexpressions of individual expressions are unsequenced. [
Note: In an expression that is evaluated more than once during the
execution of a program, unsequenced and indeterminately sequenced
evaluations of its subexpressions need not be performed consistently
in different evaluations. —end note ] The value computations of the
operands of an operator are sequenced before the value computation of
the result of the operator. If a side effect on a scalar object is
unsequenced relative to either another side effect on the same scalar
object or a value computation using the value of the same scalar
object, the behavior is undefined.
and provides the following example:
f(i = -1, i = -1); // the behavior is undefined
{a[i], b[i+1]}
etc... and incrementi
after and you won't have to worry about strange corners of the standard – Signorina