何时可以在初始化列表中省略外部大括号?

在编译下面的代码时,我在VC2010中出错C2078。

struct A { int foo; double bar; }; std::array<A, 2> a1 = // error C2078: too many initializers { {0, 0.1}, {2, 3.4} }; // OK std::array<double, 2> a2 = {0.1, 2.3}; 

我发现a1的正确语法是

 std::array<A, 2> a1 = {{ {0, 0.1}, {2, 3.4} }}; 

问题是:为什么a1需要额外的大括号,而a2不需要?

更新

这个问题似乎不是特定于std :: array。 一些例子:

 struct B { int foo[2]; }; // OK B meow1 = {1,2}; B bark1 = {{1,2}}; struct C { struct { int a, b; } foo; }; // OK C meow2 = {1,2}; C bark2 = {{1,2}}; struct D { struct { int a, b; } foo[2]; }; D meow3 = {{1,2},{3,4}}; // error C2078: too many initializers D bark3 = {{{1,2},{3,4}}}; 

我仍然不明白为什么struct D会给出错误,但是B和C不会。

额外的大括号是需要的,因为std::array是一个聚合和POD,不像标准库中的其他容器。 std::array没有用户定义的构造函数。 它的第一个数据成员是一个大小为N的数组(你作为模板parameter passing),并且这个成员是用一个初始化器直接初始化的。 正在被直接初始化的内部数组需要额外的大括号。

情况是一样的:

 //define this aggregate - no user-defined constructor struct Aarray { A data[2]; //data is an internal array }; 

你将如何初始化? 如果你这样做:

 Aarray a1 = { {0, 0.1}, {2, 3.4} }; 

它给出了一个编译错误 :

错误:“Aarray”的初始化程序过多

这是你在std::array (如果你使用GCC)的情况下得到的错误。

所以正确的做法是使用大括号如下:

 Aarray a1 = { { //<--this tells the compiler that initialization of `data` starts { //<-- initialization of `data[0]` starts 0, 0.1 }, //<-- initialization of `data[0]` ends {2, 3.4} //initialization of data[1] starts and ends, as above } //<--this tells the compiler that initialization of `data` ends }; 

编译好 。 再次,额外的大括号是需要的,因为你正在初始化内部数组。

现在的问题是,为什么double括号不需要?

这是因为double不是一个集合,而A是。 换句话说, std::array<double, 2>是聚集的集合,而std::array<A, 2>是聚集1的集合。

1.我认为在双倍的情况下(比如这个 )仍然需要额外的大括号来完全符合标准,但是代码没有它们。 看来我需要再次挖掘规格!

更多的大括号和额外的括号

我通过规范挖掘。 本节(C ++ 11的第8.5.1 / 11节)很有趣,适用于这种情况:

在表单的声明中

 T x = { a }; 

花括号可以在初始化列表中被忽略如下 。 如果初始化器列表以左大括号开始,则后续逗号分隔的初始化子句列表初始化子聚集的成员; 有比成员更多的初始化子句是错误的。 但是,如果子集合的初始化符列表不是从左括号开始,那么只有从列表中select足够的初始化子句才能初始化子集合的成员; 任何剩余的初始化子句留给初始化当前子集合所属的集合中的下一个成员。 [例如:

 float y[4][3] = { { 1, 3, 5 }, { 2, 4, 6 }, { 3, 5, 7 }, }; 

是一个完全支撑的初始化:1,3,5初始化数组y[0]的第一行,即y[0][0]y[0][1]y[0][2] 。 同样,接下来的两行初始化y[1]y[2] 。 初始化器提前结束,因此初始化y[3]s元素,就像用float()forms的expression式明确初始化一样,也就是用0.0初始化。 在以下示例中,初始化程序列表中的大括号将被省略。 然而,初始化列表与上面例子的完全支撑的初始化列表具有相同的效果,

 float y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 }; 

y的初始值设定项以左大括号开头,但是y[0]不是,因此使用列表中的三个元素。 同样,接下来的三个是为了y[1]y[2] 。 – 例子]

根据我从上面的引用中所理解的,我可以说应该允许以下几点:

 //OKAY. Braces are completely elided for the inner-aggregate std::array<A, 2> X = { 0, 0.1, 2, 3.4 }; //OKAY. Completely-braced initialization std::array<A, 2> Y = {{ {0, 0.1}, {2, 3.4} }}; 

在第一个,内部骨料的括号是完全消除,而第二个完全支撑初始化。 在你的情况下( double的情况下),初始化使用第一种方法(花括号完全消除内部聚合)。

但这应该被禁止:

 //ILL-FORMED : neither braces-elided, nor fully-braced std::array<A, 2> Z = { {0, 0.1}, {2, 3.4} }; 

它既不是大括号,也没有足够的大括号来完成初始化。 因此,它是不合格的。