#include
struct A
{
A() { std::cout << \"(A::A)\"; }
};
struct B
{
B() { std::cout << \"(B::B)\"; }
};
struct C
{
templat
It is an old bug of gcc 4.8.1 ( I suppose you use GCC) or of other compiler. I wrote about this bug several months ago the initializer-list: a bug of GCC 4.8.1
Though it is written in Russian but you can translate it into English using for example google service translate.
As it was said by others elements of the initializer-list are evaluated from left to right and all side effects are applied before evaluation of the next element.
In your second code example you in fact call the constructor with one expression that is an expression of the comma operator. The comma operator in fact behaves the same way as initializer-lists that is it evaluates its operands from left to right and applies side effects before evaluation of the next operand.
In the second instance, you're actually only initialising with B()
; through the use of the comma operator, A()
was constructed and thrown away first.
C {(A(), B())};
//|^^^^^^^^^^|
// \--------> (A(), B())
// ^^^ ^^^
// | |
// / \
// evaluated, THEN evaluated,
// discarded used
On the other hand, in the first instance, you're initialising the C
from both temporaries through an initializer list, whose elements should also be evaluated left-to-right, as it happens, but your compiler is buggy in this regard:
[C++11: 8.5.4/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. 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. [ Note: This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of the initializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call. —end note ]
I can reproduce the problem with GCC 4.8*, but Clang 3.5 behaves properly†. The bug has been discussed on the std-discussion list before‡, but I haven't found a GCC Bugzilla ID yet§.
C {A(), B()};
// ^^^ ^^^
// | \
// eval- THEN
// uated evaluated
// \ /
// \ /
// both used
* http://coliru.stacked-crooked.com/a/1f18e0d1f8973f3c
† http://coliru.stacked-crooked.com/a/5a6e7506e9be97c3
‡ https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/TQUnBFkUBDg
§ #51253 may be related.
Why in first braced init list objects are created in right-to-left order?
No. It is left-to-right. Your compiler has bug which is why it is evaluating right-to-left. GCC (4.8) is known to have this bug. Do you use GCC?
Why parentheses in second case revert this order?
Same. Left to right. In this case, comma operator comes into picture, which evaluates operands left-to-right.