авто с круглыми скобками и списком инициализации

Исходя из другого вопроса:

Поскольку С++ 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

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

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

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

(акцент мой)

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

const auto &i = expr;

Тип я - это выведенный тип параметра 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]). [ Пример:

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

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