容器列表初始化需要双括号 std::array

Double braces required for list-initialization of container std::array

用户定义类型容器的列表初始化不符合我的预期。 请参阅此片段:

#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 会产生错误,因为最多 2 个对象有 4 个初始值,但编译器会正确填写 A 的成员!为什么会这样?

在考虑任何类型信息之前,无论嵌套有多深,大括号都会与正在初始化的对象的结构相匹配。由于std::array<T,N>必须包含一个真正的T[N](而不是一个),结构是有一个对象在array——也就是数组里面。因此,使用两个左大括号来开始该数组的初始化程序,如果需要整个嵌套集来初始化一个数组元素,或者存在多个这样的嵌套集,这将不起作用。

当某些初始化器子句是表达式,甚至A{…}时,此分解停止并且初始化器用于一个子对象。但是,如果该表达式无法转换为适当子对象的类型,并且该类型本身就是聚合,则会发生 大括号省略 并且随后的初始化器用于 个子对象,尽管缺少大括号。当这适用于 T[N] 对象本身时,array 可能只用一层大括号初始化。

所以,简而言之,左括号会导致聚合分解,无论它是否有效,但是类型不匹配也会导致聚合分解。