Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do empty braces call the default constructor or the constructor taking an std::initializer_list?

The following is a quote from Effective Modern C++ (page 55):

"Suppose that you use an empty set of braces to construct an object that supports default constructor and also supports std::initializer_list construction. What do your empty braces mean? etc. The rule is that you get default construction."

I tried this with std::array:

std::array<int, 10> arr{};

and got the warning from g++ (version 4.8.2):

warning: missing initializer for member ‘std::array<int, 10ul>::_M_elems’

which is the warning one gets when trying to construct an std::array from an empty std::initializer_list (see Why can I initialize a regular array from {}, but not a std::array for a discussion of this warning).

So, why isn't the above line of code interpreted as calling the default constructor?

like image 668
AlwaysLearning Avatar asked Jul 07 '15 20:07

AlwaysLearning


1 Answers

That is because std::array is an aggregate and therefore aggregate initialization is performed this is covered in the draft C++11 standard section 8.5.4 [dcl.init.list] which says:

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).

    double ad[] = { 1, 2.0 }; // OK
    int ai[] = { 1, 2.0 }; // error: narrowing
    
    struct S2 {
      int m1;
      double m2, m3;
    };
    
    S2 s21 = { 1, 2, 3.0 }; // OK
    S2 s22 { 1.0, 2, 3 }; // error: narrowing
    S2 s23 { }; // OK: default to 0,0,0
    

and we can see if it is not an aggregate then the list goes on and says:

  • Otherwise, if T is a specialization of std::initializer_list, an initializer_list object is constructed as described below and used to initialize the object according to the rules for initialization of an object from a class of the same type (8.5).
  • Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution (13.3, 13.3.1.7). If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed.

We can confirm std::array is an aggregate from section 23.3.2.1 [array.overview]:

An array is an aggregate (8.5.1) that can be initialized with the syntax

array<T, N> a = { initializer-list };

where initializer-list is a comma-separated list of up to N elements whose types are convertible to T.

section 8.5.1 referenced is 8.5.1 Aggregates [dcl.init.aggr] and says:

When an aggregate is initialized by an initializer list, as specified in 8.5.4, the elements of the initializer list are taken as initializers for the members of the aggregate, in increasing subscript or member order [...]

and we come full-circle back to section 8.5.4 which is where we started.

like image 164
Shafik Yaghmour Avatar answered Nov 15 '22 13:11

Shafik Yaghmour