Initializer_list and default constructor overload resolution

#include <initializer_list> #include <iostream> using namespace std; struct Y {}; struct X { X(initializer_list<Y>) { cout << "yay" << endl; } explicit X() { cout << "boo" << endl; } }; X f() { return {}; } int main() { f(); return 0; } 

This produces "boo". Why doesn't he print "yay"?

Can the following two structures be distinguished:

  • X()
  • X{}

or

  • return X();
  • return {};

or

 void g(const X&) 
  • g(X())
  • g({})

Thanks.

+4
source share
4 answers

Can the following two structures be distinguished:

No. These are not different designs.

The main purpose of the {} constructor syntax was to introduce unified initialization so that the initialization work is the same everywhere. If there was a difference between them, it would not be uniform.

If you want to use the empty initializer list constructor, you must specify that you explicitly pass the initializer list. For example: return initializer_list<Y>{}; Of course, one of the other goals of uniform initialization is to not print the types of names so much, so you can achieve the same effect with return {{}};

+5
source

return {}; will always use the default constructor, if any.

return X({}); or return {{}}; will be created from an empty initialization list.

+5
source

It uses the default constructor because initializing a list with {} should be a short form of initializing a value always, without considering other constructors, even if they are constructors of an initializer list.

Is it necessary to distinguish the following two constructions: ...

X() always initialized with a value, and X{} is only the initialization of the value if X has a default constructor. If it is an aggregate, then X{} represents aggregate initialization (initialization of elements of X to {} recursive). If it has only initializer list constructors and default constructors, then X() is invalid and X{} may be valid

 struct A { A(initializer_list<int>); }; A a = A{}; // valid A b = A(); // invalid 

Essentially, that X{} really depends on what X But X() always initializes the value.

... or return X (); vs return {};

Something subtle to mention ... In return {} target is initialized with a list-list, and in return X(); first, the line initializes X But even though it is initialized using the list of copies, it can use the default constructor explicit by default, since initializing the value does not care about explicit . However, when you execute return {} and try to use an explicit constructor other than the standard, you will be mistaken

 struct A { explicit A(initializer_list<int>); }; A f() { return {}; } // error! struct B { explicit B(); }; B g() { return {}; } // OK 
+1
source

You may be more explicit:

 return initializer_list<Y>(); 
0
source

Source: https://habr.com/ru/post/1393194/


All Articles