带有括号和初始化列表的自动
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 ]
来自
从 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 ]