39

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!

zneak
  • 134,922
  • 42
  • 253
  • 328
Bikineev
  • 1,685
  • 15
  • 20
  • no, clang-3.5 and gcc-4.9 compiles it with -std=c++1y – Bikineev May 27 '14 at 06:33
  • 2
    I would find that surprising. It looks like a breaking change. It has to be value initialization, and if it were well formed it would negate some of the reasons for having deleted special functions. – juanchopanza May 27 '14 at 06:42
  • I lean towards aggregate initialization. It has bigger priority if type is aggregate. – Bikineev May 27 '14 at 06:43
  • 2
    I'm looking at the latest draft, N3936 and don't see how this can compile. But you're right that both clang 3.4 and gcc-4.9 do compile it with `-std=c++1y`. gcc-4.8 doesn't and complains about the deleted constructor. – Praetorian May 27 '14 at 06:43
  • 1
    Maybe with this scheme they want to provide a mean of POD only struct or something. – 101010 May 27 '14 at 06:47
  • @40two, indeed, adding a virtual method to the class makes the compilation fail again. – zneak May 27 '14 at 06:48
  • 2
    `In all cases, if the empty pair of braces {} is used and T is an aggregate type, aggregate-initialization is performed instead of value-initialization.` Your `struct A` is an (empty) aggregate. – user703016 May 27 '14 at 06:49
  • @zneak, 40two adding a member like string, which is not pod, does still [compile](http://coliru.stacked-crooked.com/a/2ba90540d4d8f6c2) though – KillianDS May 27 '14 at 06:49
  • @Praetorian Found it: in §8.5.4 / 3: "***If T is an aggregate, aggregate initialization is performed (8.5.1).***" (See the last example, which is just before the first quote in your deleted answer.) – juanchopanza May 27 '14 at 06:59

2 Answers2

30

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.

user703016
  • 37,307
  • 8
  • 87
  • 112
  • 1
    *"(explicitly defaulted or deleted constructors are allowed)"*.. says who? there lies the answer, so please quote the spec. – Nawaz May 27 '14 at 09:34
  • Note that the last bullet point in your "it is an aggregate" list does not apply in C++1y. – juanchopanza May 27 '14 at 09:54
20

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.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • 3
    +1 It's the *user provided* clause that threw me off. I assumed explicitly defaulted/deleted constructor counted as user provided. – Praetorian May 27 '14 at 07:06
  • 1
    *"A is an aggregate"*. How exactly? Your quote should prove that first. – Nawaz May 27 '14 at 09:37
  • @Nawaz "A special member function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration." – juanchopanza May 27 '14 at 09:45
  • @Nawaz I added some quotes and an explanation. – juanchopanza May 27 '14 at 09:53
  • 2
    +1 for *"A function is user-provided if it is user-declared and not explicitly defaulted **or deleted on its first declaration**."* .... The *deleted* part surprised me! – Nawaz May 27 '14 at 09:59
  • 2
    @Nawaz I always have to look up this "user-provided" business. Hopefully I will remember it from now on. But it doesn't help that [some compilers seem to get this wrong](http://ideone.com/n3q3kO). – juanchopanza May 27 '14 at 10:02
  • So, is this a defect in the standard? – Yakk - Adam Nevraumont May 27 '14 at 13:15
  • @Yakk I am actually not sure, but it seems likely, given the change shown above. It also makes aggregate initialization more consistent. The problem is that the issue is confounded by what some compilers do. For instance, [this example](http://ideone.com/n3q3kO) should compile in C++11. Also, OP's the example probably shouldn't, yet clang 3.4 accepts it. – juanchopanza May 27 '14 at 18:03
  • 2
    @Yakk yes, I tend to consider this a defect. Deleting the constructor was supposed to be the clean version of supplying a private, empty one... – Massa May 27 '14 at 20:43