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.