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.
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 .
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.
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.
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.
§13.3.1.7 [over.match.list]/p1:
When objects of non-aggregate class type
Tare 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
Tand 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
Tand the argument list consists of the elements of the initializer list.If the initializer list has no elements and
Thas a default constructor, the first phase is omitted. In copy-list-initialization, if anexplicitconstructor 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With