Reputation: 1777
I have some misunderstanding:
Let's mark default constructor of struct A as deleted:
struct A
{
A() = delete;
};
The next instruction is well-formed and what's that effect?:
A a{};
From cppreference value initilization:
1) If T is a class type with no default constructor or with a user-provided default constructor or with a deleted default constructor, the object is default-initialized.
but then the effect of default initialization is:
If T is a class type, the default constructor is called to provide the initial value for the new object.
Or it's aggregate initialization? Thanks!
Upvotes: 40
Views: 3195
Reputation: 37945
Your struct A
is :
It therefore qualifies as an aggregate type, according to the definition provided by § 8.5.1/1.
Then comes the priority of aggregate initialization over value initialization. The standard says that aggregate initialization has precedence over value intialization (draft N3936, § 8.5.4/3, page 201) (emphasis mine)
List-initialization of an object or reference of type T is defined as follows:
- If T is an aggregate, aggregate initialization is performed (8.5.1).
- Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.
- [... more rules...]
(1) As requested in the comments on why a deleted constructor does not count as user-defined, here is what the standard says (draft N3936, § 8.4.2/5, page 198):
A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration.
Upvotes: 31
Reputation: 227390
It is well formed. A
is an aggregate1, and, according to draft N3936, an empty initializer list used in direct-list initialization of an aggregate results in aggregate initialization:
From § 8.5.4/3 List-initialization [dcl.init.list]:
List-initialization of an object or reference of type T is defined as follows:
— If T is an aggregate, aggregate initialization is performed (8.5.1).
[ Example:
struct S2 { int m1; double m2, m3; };
....
S2 s23{}; // OK: default to 0,0,0
....
— end example ]
....
The relevant changes between C++11 and C++1y are a change in the precedence of aggregate vs. value initialization for the case of aggregates:
C++11 leads with
List-initialization of an object or reference of type T is defined as follows:
— If the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.
— Otherwise, if T is an aggregate, aggregate initialization is performed (8.5.1)....
followed by the example above.
C++1y gives priority to aggregate initialization:
List-initialization of an object or reference of type T is defined as follows:
— If T is an aggregate, aggregate initialization is performed (8.5.1).
....
— Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.
1 Why is A
an aggregate?
It is an aggregate both in C++11 and C++14.
C++1y:
8.5.1 Aggregates [dcl.init.aggr]
An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).
The only part that is not obvious is whether the defaulted constructor is user-provided or not. It isn't:
In § 8.4.2 [dcl.fct.def.default]:
A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration.
Upvotes: 20