This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115e. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-11-11
Issue 1815 presented a subset of the following examples:
struct A {}; struct B { A&& a = A{}; }; B b1; // #1, default-initialization B b2{A{}}; // #2, aggregate initialization B b3{}; // #3, aggregate initialization B b4 = B(); // #4, value-initialization B b5(A{}); // #5, aggregate initialized via parentheses (9.4.1 [dcl.init.general] bullet 16.6.2.2) struct C { int i; A&& a = A{}; }; C c6(1); // #6, aggregate initialized via parentheses A a7 = C(1).a; // #7, aggregate initialized via parentheses
Issue 1696 was adopted, ostensibly resolving issue 1815, but the wording changes in 11.9.3 [class.base.init] paragraph 11 affected only the behavior of constructors, not of aggregate initialization:
A temporary expression bound to a reference member from a default member initializer is ill-formed. [ Example:struct A { A() = default; // OK A(int v) : v(v) { } // OK const int& v = 42; // OK }; A a1; // error: ill-formed binding of temporary to reference A a2(1); // OK, unfortunately-- end example]
There is considerable implementation variance: #1 is rejected by clang, but accepted by gcc and EDG (with early destruction of the temporary); #2 is uniformly accepted and the lifetime of the temporary is extended; #3 is uniformly accepted, but only gcc, clang, and MSVC extend the lifetime of the temporary, whereas EDG does not.
Note that 9.4.1 [dcl.init.general] paragraph 7 specifies that default-initialization of aggregates is as-if the initializer () is used:
To default-initialize an object of type T means:
- If T is a (possibly cv-qualified) class type (Clause 11 [class]), constructors are considered. The applicable constructors are enumerated (12.2.2.4 [over.match.ctor]), and the best one for the initializer () is chosen through overload resolution (12.2 [over.match]). The constructor thus selected is called, with an empty argument list, to initialize the object.
- If T is an array type, each element is default-initialized.
- Otherwise, no initialization is performed.
Such treatment causes early destruction of temporaries per 6.7.7 [class.temporary] bullet 6.10:
The exceptions to this lifetime rule are:
- ...
- A temporary object bound to a reference element of an aggregate of class type initialized from a parenthesized expression-list (9.4 [dcl.init]) persists until the completion of the full-expression containing the expression-list.
CWG 2023-05-12
CWG is soliciting the design guidance of EWG to resolve this issue, in particular for examples #3 and #6. For each of the presented examples, the standard should say whether the use is well-formed or not and whether the lifetime of the temporary is extended. It is also conceivable to implicitly delete the constructor being invoked (if any).
Forwarded to EWG via cplusplus/papers#1511.