С CPP reference по-списка инициализации:List-инициализатор и VARIADIC конструктор
В противном случае, конструкторы Т рассматриваются в два этапа:
Все конструкторы, которые принимают зЬй :: initializer_list в качестве единственного аргумента или в качестве первого аргумента, если остальные аргументы имеют значения по умолчанию, проверяются и сопоставляются разрешением перегрузки по одному аргументу типа std :: initializer_list
Если предыдущий этап не дает соответствия, все конструкторы T участвуют в разрешении перегрузки против множества аргументов, которые состоят из элементов списка с привязкой-инициализацией, с ограничением, допускающим только не суживающиеся преобразования. Если эта стадия создает явный конструктор, как лучший матч для копирования списка инициализации, компиляция завершится неудачно (обратите внимание, в простой копии инициализации, явные конструкторы вообще не рассматривается)
Так конструктор с использованием initializer_list
считается первым. В противном случае каждый элемент списка рассматривается как аргументы для конструкторов. Однако
#include <iostream>
using namespace std;
struct A{
template <typename... Args> A(Args... li) { cout << sizeof...(Args) << endl;}
};
int main(){
A a = {2,3,4};
}
Выход 3
, который указывает на то, что Args...
распаковывается как int, int, int
. Почему Args ... не просто сделал единственное число initializer_list<int>
, которое указано в указателе на инициализацию списка, это будет первый тип типа конструктора?
Чтобы быть понятным, аргумент 'initializer_list' приведет к успешному вычитанию аргумента шаблона в 'A (Args ...)'.Таким образом, первая строка моей цитаты CPP (преобразование в аргумент 'initialiser_list') применяется к поиску конструкторов кандидатов без шаблонов, в то время как ваша цитата относится к поиску функций шаблона-кандидата с использованием вычитания аргумента шаблона. Если ни шаблонные, ни шаблонные функции не предоставляют подходящего кандидата, каждый элемент списка рассматривается как отдельный аргумент. –
AntiElephant
Есть примечание в ** [dcl.init.list]/2 **: «Передача списка инициализатора в качестве аргумента шаблона конструктора» template C (T) 'класса' C' не создает инициализатор -list, потому что аргумент списка инициализатора приводит к тому, что соответствующий параметр является не выводимым контекстом (14.8.2.1). " Вот что привело меня к ** [temp.deduct.call] **. Теперь верно, что изменение 'main' в вашей программе на' std :: initializer_list l {2,3,4}; A a = l; 'компилируется. Я не знаю, почему. –
Ах. ** [temp.deduct.call]/1 ** говорит о случае, когда аргумент представляет собой список инициализаторов (то есть последовательность разделенных запятыми значений, заключенных в фигурные скобки), а не экземпляр 'std :: initializer_list' , Различие важно, они не взаимозаменяемы. –