auto с круглыми скобками и списком инициализаторов - PullRequest
0 голосов
/ 04 июля 2018

Подходит от другой вопрос :

Поскольку C ++ 17, auto x0{1, 2, 3, 4};, ранее выводивший список инициализаторов, больше не разрешен (конечно, мы можем использовать auto x0 = {1, 2, 3, 4}; вместо этого ...). Теперь, как всегда, избегая равномерной инициализации (например, std::vector<int> v({1, 2, 3, 4});, т.е. явный вызов конструктора со списком инициализатора в качестве аргумента) и по аналогии с четко определенной auto x(7); (конструкцией, которую я сам никогда не буду использовать. ..) я придумал следующее:

auto x({1, 2, 3, 4});
// -> std::initializer_list<int> x({1, 2, 3, 4});

Это скомпилировано с GCC 7.2.0 (mingw64), но выдало предупреждение (в то время как прокомментированная версия снова нет):

list-initializer for non-class type must not be parenthesized

Я не смог найти что-либо релевантное в стандарте, поэтому теперь вопрос (из чистого интереса ...):

Почему это не разрешено? (Это покрыто стандартом или мы должны считать это ошибкой GCC?)

1 Ответ

0 голосов
/ 04 июля 2018

Это плохо сформировано. Короче говоря, braced-init-list не может быть выведен при выводе аргумента шаблона, он рассматривается как невыгружаемый контекст .

6) Параметр P, чей A является списком фигурных скобок инициализации, но P не является std :: initializer_list или ссылкой на него:

Во-первых, автоматическое удержание типа использует правила вывода аргумента шаблона из вызова функции . [dcl.type.auto.deduct] / 4

(акцент мой)

Если заполнитель является автоматическим спецификатором типа, выводимый тип T ' замена T определяется с использованием правил для аргумента шаблона вычет. Получить P из T, заменив вхождения auto на либо новый параметр шаблона изобретенного типа U, либо, если инициализация - копирование-список-инициализация, с std​::​initializer_­list<U>. Выведите значение для U, используя правила вывод аргумента шаблона из вызова функции, где P - это Тип параметра шаблона функции и соответствующий аргумент - e. Если вычет не удался, декларация неверна. [Пример:

const auto &i = expr;

Тип i - это выведенный тип параметра u в вызове f (expr) следующего изобретенного шаблона функции:

template <class U> void f(const U& u);

- конец примера]

Обратите внимание, что auto x({1, 2, 3, 4}); - это прямая инициализация, а не инициализация копирования, тогда параметр шаблона изобретенного типа - это просто U, а не std​::​initializer_­list<U>, а соответствующий аргумент - {1, 2, 3, 4}.

А в выводе аргумента шаблона из вызова функции , параметр шаблона не может быть выведен из списка braced-init-list. [temp.deduct.call] / 1

Вывод аргумента шаблона выполняется путем сравнения каждого типа параметра шаблона функции (назовите его P), который содержит параметры шаблона, которые участвуют в выводе аргумента шаблона, с типом соответствующего аргумента вызова (назовите его A), как описано ниже. Если удаление ссылок и cv-квалификаторов из P дает std :: initializer_list или P '[N] для некоторых P' и N, а аргумент является непустым списком инициализатора ([dcl.init.list]), то вычет вместо этого выполняется для каждого элемента списка инициализатора, принимая P 'в качестве типа параметра шаблона функции и элемент инициализатора в качестве аргумента, а в случае P' [N], если N является параметром шаблона нетипичного типа, N выводится из длины списка инициализатора. В противном случае аргумент списка инициализатора приводит к тому, что параметр считается неделедированным контекстом ([temp.deduct.type]). [Пример: * +1043 *

template<class T> void g(T);
g({1,2,3});                     // error: no argument deduced for T

- конец примера]

...