由于以前不允许推导初始化程序列表的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);
(我不会构造曾经使用过自己...),我想到了以下内容:
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错误?)
答案 0 :(得分:6)
这是错误的形式。简而言之,无法在模板参数推导中推导出braced-init-list,它被视为non-deduced context。
6)参数P,它的A是一个括号初始化列表,但P不是std :: initializer_list或对一个的引用:
首先,自动类型推导使用函数调用中模板参数推导的规则。 [dcl.type.auto.deduct]/4
(重点是我的)
如果占位符是自动类型说明符,则推导类型T' 使用模板参数规则确定替换T 扣除。 从T中获取P,方法是将auto替换为 新的发明类型模板参数U,或者 初始化是复制列表初始化,带有
std::initializer_list<U>
。使用以下规则推导U的值 从函数调用中推导出模板参数,其中P是一个 函数模板的参数类型和对应的参数为e。 如果推导失败,则声明格式错误。 [示例:const auto &i = expr;
i的类型是以下发明函数模板的调用f(expr)中参数u的推导类型:
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)进行比较来完成的,如下所述。如果从P删除引用和cv限定词将给出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
-示例]