2015-11-26 3 views
3

С 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>, которое указано в указателе на инициализацию списка, это будет первый тип типа конструктора?

ответ

4

[temp.deduct.call]/1 Шаблон вывод аргумента делается путем сравнения каждой функции тип параметра шаблона (назовем его P) с типом соответствующего аргумента вызова (назовем его A), как описано ниже. Если удаление ссылок и cv-квалификаторов от P дает std::initializer_list<P'> для некоторого P', и аргумент представляет собой список инициализаторов (8.5.4), то вместо каждого элемента списка инициализатора выполняется дедукция, принимающая P' как тип параметра шаблона функции и инициализатор в качестве аргумента. В противном случае аргумент списка инициализатора приводит к тому, что параметр считается невыводимым контекстом (14.8.2.5).

Emphasis mine. По этой причине вывод аргумента шаблона для конструктора из аргумента типа initializer_list<int> терпит неудачу.

+0

Чтобы быть понятным, аргумент 'initializer_list ' приведет к успешному вычитанию аргумента шаблона в 'A (Args ...)'.Таким образом, первая строка моей цитаты CPP (преобразование в аргумент 'initialiser_list') применяется к поиску конструкторов кандидатов без шаблонов, в то время как ваша цитата относится к поиску функций шаблона-кандидата с использованием вычитания аргумента шаблона. Если ни шаблонные, ни шаблонные функции не предоставляют подходящего кандидата, каждый элемент списка рассматривается как отдельный аргумент. – AntiElephant

+0

Есть примечание в ** [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; 'компилируется. Я не знаю, почему. –

+0

Ах. ** [temp.deduct.call]/1 ** говорит о случае, когда аргумент представляет собой список инициализаторов (то есть последовательность разделенных запятыми значений, заключенных в фигурные скобки), а не экземпляр 'std :: initializer_list' , Различие важно, они не взаимозаменяемы. –

1

Если вы предоставляете явно конструктор с std::initializer_list, он будет выбирать: Demo.

template <typename... Args> A(Args...) не является конструктором с первым аргументом std::initializer_list (даже если первый аргумент может быть std::initializer_list).

И в A a = {2, 3, 4}, {2, 3, 4} не имеет типа. Это не std::initializer_list.

Смежные вопросы