I -believe- that what I'm trying to do is probably valid because it is separated in both instances by a comma (not a typical assignment), but I have no idea for sure and search isn't bringing up anything about these two specific situations.
In both cases, I was using the variable as an index for two parallel arrays.
int a[3] = {10, 20, 30};
int b[3] = {20, 40, 60};
Situation #1: Initializing a struct for the arrays
struct testStruct {
int t1;
int t2;
};
int i = 0;
testStruct test = {a[++i], b[i]}
Expected result of final line: test = {20, 40}
Situation #2: Passing specific values from the arrays as function args
void testFunc(int t1, int t2) {
// do stuff
}
int i = 0;
test(a[++i], b[i]);
Expected result of final line: test(20, 40)
Is this valid code? And if it is, is it valid in all compilers?
Is the result what I expect? If so, is it because of the arrays or because of the comma?
Thanks!
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