-
Notifications
You must be signed in to change notification settings - Fork 7
Description
Full name of submitter (unless configured in github; will be published with the issue): Tam S. B.
Reference (section label): [dcl.init.general] [dcl.init.list]
Link to reflector thread (if any):
Issue description:
Otherwise, if the destination type is a class type:
- If the initializer expression is a prvalue [...]
- Otherwise, if the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same as or is derived from the class of the destination type, constructors are considered. The applicable constructors are enumerated ([over.match.ctor]), and the best one is chosen through overload resolution ([over.match]). Then:
- If overload resolution is successful, the selected constructor is called to initialize the object, with the initializer expression or
expression-list
as its argument(s).- Otherwise, if no constructor is viable, the destination type is an aggregate class, and the initializer is a parenthesized
expression-list
, the object is initialized as follows. Let e1, …, en be the elements of the aggregate ([dcl.init.aggr]). Let x1, …, xk be the elements of theexpression-list
. If k is greater than n, the program is ill-formed. The element ei is copy-initialized with xi for 1 ≤ i ≤ k. The remaining elements are initialized with their default member initializers, if any, and otherwise are value-initialized. For each 1≤i<j≤n, every value computation and side effect associated with the initialization of ei is sequenced before those associated with the initialization of ej.- Otherwise, the initialization is ill-formed.
Consider
struct B;
struct A {
A();
A(A&); // copy constructor
A(const B&); // converting constructor
};
struct B {
A a;
// implicit default constructor: B();
// implicit copy constructor: B(B&);
};
const B b1;
const B b2(b1); // #1
const B b3{b1}; // #2
For b2
, since neither B()
nor B(B&)
is viable, the parenthesized aggregate initialization takes place, which initializes b2
as if by const B b2{.a = b1}
.
For b3
, [dcl.init.list]/(3.2) is in effect, which reads:
If
T
is an aggregate class and the initializer list has a single element of type cv1U
, whereU
isT
or a class derived fromT
, the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).
This would invoke [dcl.init.general]/(16.6), but in this case, it's unclear whether the initializer is a a parenthesized expression-list
, and thus unclear whether parenthesized aggregate initialization should apply.
Clang 21 (not yet released at the time of writing) permits both initializations, while all other compilers (including Clang 20.1.0) reject both.
In my opinion both initializations should be invalid.
Suggested resolution:
Modify [dcl.init.general]/(16.6.2.2) as indicated:
- Otherwise, if no constructor is viable, the destination type is an aggregate class,
andthe initializer is a parenthesizedexpression-list
, and, if theexpression-list
has a single element of type cvU
,U
is neither the same as nor derived from the class of the destination type, the object is initialized as follows. [...]