Bikineev
Bikineev

Reputation: 1777

C++14 value-initialization with deleted constructor

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

Answers (2)

user703016
user703016

Reputation: 37945

Your struct A is :

  • a class type that has:
    • no user-provided constructors1,
    • no private or protected non-static data members,
    • no base classes,
    • no virtual member functions.

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

juanchopanza
juanchopanza

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

Related Questions