额外的大括号是必需的,因为
std::array
是一个聚合体和POD,不同于标准库中的其他容器。
std::array
没有用户定义的构造函数。它的第一个数据成员是大小为
N
的数组(您将其作为模板参数传递),并且该成员直接使用初始化程序进行初始化。 额外的大括号用于直接初始化的
内部数组。
情况与以下情况相同:
//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}
};
出现了编译错误compilation error:
错误: 'Aarray' 的初始值设定项太多
如果你使用GCC编译,std::array
会产生相同的错误。
因此,正确的做法是使用大括号,如下所示:
Aarray a1 =
{
{
{
0, 0.1
},
{2, 3.4}
}
};
这段代码编译良好。再次强调,额外的花括号是必须的,因为你正在初始化内部数组。
--
现在的问题是为什么在
double
的情况下不需要额外的大括号?
这是因为double
不是一个聚合类型,而A
是。换句话说,std::array<double, 2>
是一个聚合的聚合类型,而std::array<A, 2>
是一个聚合的聚合的聚合类型1。
1. 我认为在double
的情况下也仍然需要额外的大括号(例如this),才能完全符合标准,但是代码可以在没有它们的情况下工作。看来我需要再次查阅规范!。
关于大括号和额外的大括号
我查阅了规范。这个章节(来自C++11的§8.5.1/11)非常有趣,并适用于这种情况:
在形式为
T x = { a };
“花括号可以在初始化列表中省略,方法如下。如果初始化列表以左花括号开头,则随后用逗号分隔的初始化子句列表将初始化子聚合体的成员;初始化子句的数量不能超过成员数量,否则会出错。但是,如果子聚合体的初始化列表不以左花括号开头,则只需要从列表中取足够的初始化子句来初始化子聚合体的成员;任何剩余的初始化子句将用于初始化当前子聚合体所属的聚合体的下一个成员。 [示例:”
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]的元素被初始化为0.0。在下面的例子中,初始化列表中的大括号被省略了;但是初始化列表具有与上面示例中完全支撑的初始化列表相同的效果。
float y[4][3] = {
1, 3, 5, 2, 4, 6, 3, 5, 7
};
根据我从上述引用中理解的内容,我可以说应该允许以下操作:y的初始化以左大括号开始,但是y[0]的初始化没有,因此列表中的三个元素被使用。同样,接下来的三个元素连续用于y[1]和y[2]。——示例结束]
std::array<A, 2> X =
{
0, 0.1,
2, 3.4
};
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}
};
它既不是省略了大括号的初始化,也没有足够的大括号来进行完全初始化。因此,它是不合法的。
double
不是一个聚合体,而A
是。换句话说,std::array<double, 2>
是一个聚合体的聚合体,而std::array<A, 2>
是一个聚合体的聚合体的聚合体! - Nawazstd::array<double, 2> a2 = {{0.1, 2.3}};
,但我也想知道为什么允许省略一对大括号。 - Andriy