带有括号和初始化列表的自动

auto with parentheses and initialiser list

来自

从 C++17 开始,不再允许 auto x0{1, 2, 3, 4}; 之前推导初始化列表(当然,我们可以使用 auto x0 = {1, 2, 3, 4};...)。现在一如既往地避免统一初始化(例如 std::vector<int> v({1, 2, 3, 4});,即 explicit 构造函数调用,以初始化列表作为参数)并且类似于定义良好的 auto x(7); (构造 I我自己也不会用...),我想到了以下内容:

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 错误?)

这是错误的格式。简而言之,braced-init-list 不能在模板参数推导中推导,它被认为是 non-deduced context.

6) The parameter P, whose A is a braced-init-list, but P is not std::initializer_list or a reference to one:

首先,自动类型推导使用从函数调用中推导模板参数的规则[dcl.type.auto.deduct]/4

(强调我的)

If the placeholder is the auto type-specifier, the deduced type T' replacing T is determined using the rules for template argument deduction. Obtain P from T by replacing the occurrences of auto with either a new invented type template parameter U or, if the initialization is copy-list-initialization, with std​::​initializer_­list<U>. Deduce a value for U using the rules of template argument deduction from a function call, where P is a function template parameter type and the corresponding argument is e. If the deduction fails, the declaration is ill-formed. [ Example:

const auto &i = expr;

The type of i is the deduced type of the parameter u in the call f(expr) of the following invented function template:

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

— end example ]

注意auto x({1, 2, 3, 4});是直接初始化,不是复制初始化,那么发明的类型模板参数就是U,不是std​::​initializer_­list<U>,对应的实参是{1, 2, 3, 4}.

并且在函数调用的模板参数推导中,模板参数不能从braced-init-list推导。 [temp.deduct.call]/1

Template argument deduction is done by comparing each function template parameter type (call it P) that contains template-parameters that participate in template argument deduction with the type of the corresponding argument of the call (call it A) as described below. If removing references and cv-qualifiers from P gives std​::​initializer_­list or P'[N] for some P' and N and the argument is a non-empty initializer list ([dcl.init.list]), then deduction is performed instead for each element of the initializer list, taking P' as a function template parameter type and the initializer element as its argument, and in the P'[N] case, if N is a non-type template parameter, N is deduced from the length of the initializer list. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context ([temp.deduct.type]). [ Example:

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

— end example ]