Is the following perfectly defined:
int x = 42, y = x;
i.e. strictly equivalent to:
int x = 42;
int y = x;
<
This question came up in comp.lang.c++.moderated a long time ago under the topic init-declarator-list analysis order and the conclusion there was Yes
.
Although I see the full-expression argument but I do not see the order of evaluation argument. So I think this is unspecified.
The relevant part of the question is:
In this declaration and definition:
int a = 2, b = a;
Is it guaranteed that b will always be initialized as 2 ? If yes, then can we say that a = 2 is always analysed(or evaluated?) before b = a ?
and the relevant part of the answer is:
Yes. Strictly stated, the observable behavior of the program must be as if all of the side effects of the 'a = 2' part of the declaration took place before the evaluation of the 'b = a' part starts. (In practice, of course, in this simple example, a compiler could assign 2 to both a and b in any order, or even in parallel, because doing so would result in the same observable behavior.)
and further down:
In this particular case, however, it does separate the declarator list into separate declarators; each declarator contains a complete expression, and the declarators are evaluated in order.
Update
What makes each init-declator a full expression is subtle but as far as I can tell follows the same logic I used in Are multiple mutations of the same variable within initializer lists undefined behavior pre C++11. In this case we start from the grammar defined in ection 8:
init-declarator-list:
init-declarator
init-declarator-list , init-declarator
init-declarator:
declarator initializeropt
The next point of focus is the initializer grammar which is covered in section 8.5
:
initializer:
brace-or-equal-initializer
( expression-list )
brace-or-equal-initializer:
= initializer-clause
braced-init-list
initializer-clause:
assignment-expression
braced-init-list
In both cases we have = initializer-clause which bring us to assignment-expression which if we follow the grammar in section 5 bring us back to primary-expression which can give us either a literal or id-expression.
So we do indeed have full-expressions separated by a grammatical comma so we have:
int x = 42, y = x;
^ ^
| end full-expression
end full-expression
and according to section 1.9
paragraph 14 we see that:
Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.8.
As for the order of evaluation, I think this is not specified, the same logic that applies to defect report 430 for initializer lists would seem to apply here as well. In C++11 the language for initializer lists was fixed with the following addition in section 8.5.4
:
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. [...]
there is no such equivalent for initializer.
The correct answer is that
int x = 42, y = x;
and
int x = 42;
int y = x;
are usually equivalent (not strictly).
Considering the standard § 8 Declarators [dcl.decl]:
3
Each init-declarator in a declaration is analyzed separately as if it was in a declaration by itself.
and in the footnote [100] further explains:
A declaration with several declarators is usually equivalent to the corresponding sequence of declarations each with a single declarator. That is
T D1, D2, ... Dn;
is usually equivalent to
T D1; T D2; ... T Dn;
where T is a decl-specifier-seq and each Di is an init-declarator.
The above guarantees that x = 42
and y = x
will be evaluated separately. However, as @Praetorian correctly pointed out in the comments, footnotes are not normative.
This means that the order of evaluation is not well defined and an implementer could as well implement the evaluation of the declarations in the reverse order (i.e,. T Dn; ...T D2; T D1;
).
One might argue that the comma operator is guaranteed left to right evaluation. However, this not the case. According to the K & R [K & R II, 3.6 p.63], that also applies to C++:
The commas that separate function arguments, variables in declarations, etc., are not comma operators, and do not guarantee left to right evaluation.