Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the std::initializer_list constructor preferred when using a braced initializer list?

Consider the code

#include <iostream>  class Foo {     int val_; public:     Foo(std::initializer_list<Foo> il)     {         std::cout << "initializer_list ctor" << std::endl;     }     /* explicit */ Foo(int val): val_(val)     {         std::cout << "ctor" << std::endl;     }; };  int main(int argc, char const *argv[]) {     // why is the initializer_list ctor invoked?     Foo foo {10};  } 

The output is

ctor initializer_list ctor 

As far as I understand, the value 10 is implicitly converted to a Foo (first ctor output), then the initializer constructor kicks in (second initializer_list ctor output). My question is why is this happening? Isn't the standard constructor Foo(int) a better match? I.e., I would have expected the output of this snippet to be just ctor.

PS: If I mark the constructor Foo(int) as explicit, then Foo(int) is the only constructor invoked, as the integer 10 cannot now be implicitly converted to a Foo.

like image 825
vsoftco Avatar asked Nov 26 '14 08:11

vsoftco


People also ask

What is Initializer_list constructor?

An object of type std::initializer_list<T> is a lightweight proxy object that provides access to an array of objects of type const T .

What is a constructor initializer list and what are its uses C++?

Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. Following is an example that uses the initializer list to initialize x and y of Point class.

When should a constructor use an initializer?

Initialization lists allow you to choose which constructor is called and what arguments that constructor receives. If you have a reference or a const field, or if one of the classes used does not have a default constructor, you must use an initialization list.

What is the advantage of initializer list in C ++?

The most common benefit of doing this is improved performance. If the expression whatever is the same type as member variable x_, the result of the whatever expression is constructed directly inside x_ — the compiler does not make a separate copy of the object.


1 Answers

§13.3.1.7 [over.match.list]/p1:

When objects of non-aggregate class type T are list-initialized (8.5.4), overload resolution selects the constructor in two phases:

  • Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class T and the argument list consists of the initializer list as a single argument.
  • If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list.

If the initializer list has no elements and T has a default constructor, the first phase is omitted. In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed.

As long as there is a viable initializer-list constructor, it will trump all non-initializer-list constructors when list-initialization is used and the initializer list has at least one element.

like image 54
T.C. Avatar answered Sep 21 '22 16:09

T.C.