要初始化容器 std::array,需要使用双重花括号进行列表初始化。

3

用户定义类型的容器列表初始化的行为并不像我期望的那样。看下面这段代码片段:

#include <array>

struct A {
    char C;
    int s;
};

int main(int argc, char * argv[]) {
    A x = {'x'}, y = {'y'};

    std::array<int, 2> i = {1, 2}; // Ok

    std::array<A, 2> a = {x, y}; // Ok
    //std::array<A, 2> b =  { {'x',1000}, {'y',2000} }; // Error: too many initializers!!!
    std::array<A, 2> c = { A{'x',1000}, A{'y',1000} };
    std::array<A, 2> d = {{ {'x',1000}, {'y',1000} }}; // Ok!!
    std::array<A, 2> e = {'x', 2000, 'y', 5000}; // Ok!!
} 

我可以像初始化基本数组一样初始化i。只要它们是变量,我也可以使用相同的方法初始化a。但是我不能在不指定类型A的情况下初始化b,就像在c中一样。

  1. 要在不显式声明类型A的情况下初始化std::array,我必须添加另一对大括号。为什么需要双层大括号呢?为什么不能像b中那样用一对大括号围绕列表进行初始化呢?

  2. 出人意料的是,c有效且只生成了两个对象!直觉上,我会期望e会产生错误,因为有4个初始值和最多只能容纳2个对象,但是编译器正确地填充了A的成员!为什么会发生这种情况?


1
这个答案解决了一个类似于1)的问题,但是2)没有得到回答。 - Arjonais
1个回答

4
无论嵌套多深,花括号都会先与被初始化的对象结构匹配,再考虑类型信息。由于 std::array<T,N> 必须包含一个真正的 T[N](而不是成为一个),因此其结构是数组内只有一个对象,即该数组本身。因此,如果需要整个嵌套集来初始化一个数组元素,或者存在多个这样的嵌套集,则两个开放的大括号将无法开始该数组的初始化程序。
当某个初始化程序子句是表达式时,即使是 A{...},这个分解也会停止,并且该初始化程序将用于一个子对象。但是,如果该表达式无法转换为适当子对象的类型,且该类型本身是聚合类型,则会进行花括号省略,并且后续的初始化程序将用于它的子对象,尽管没有花括号。当这适用于 T[N] 对象本身时,array 可以只用一层花括号进行初始化。
因此,简而言之,一个左花括号会导致聚合体的分解,无论是否成功,但类型不匹配也会导致聚合体的分解。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接