为什么在C++ 14中对数组的初始化仍然需要双括号?

Chi*_*iel 62 c++ initializer-list c++14

使用C++ 14标准,std::array可以使用单个括号进行初始化(请参阅http://en.cppreference.com/w/cpp/container/array):

然而,这并没有为工作std::arraystd::pair.

为什么这些工作:

std::pair<int, int> p { 1, 2 };
std::array<int, 3> a {1, 2, 3};
Run Code Online (Sandbox Code Playgroud)

但是这工作:

std::array<std::pair<int, int>, 3> b {{1, 11}, {2, 22}, {3, 33}};
Run Code Online (Sandbox Code Playgroud)

虽然这确实有效吗?

std::array<std::pair<int, int>, 3> b {{{1, 11}, {2, 22}, {3, 33}}};
Run Code Online (Sandbox Code Playgroud)

此外,为了完成,一个好的旧数组的初始化确实适用于单个大括号

std::pair<int, int> c[3] {{1, 11}, {2, 22}, {3, 33}};
Run Code Online (Sandbox Code Playgroud)

Jod*_*cus 30

这似乎是一个解析的怀疑,有点类似于着名的 最令人烦恼的解析.我怀疑发生了什么:

如果你写

std::array<std::pair<int, int>, 3> b {{1, 11}, {2, 22}, {3, 33}};
Run Code Online (Sandbox Code Playgroud)

编译器有两种解释语法的方法:

  1. 您执行全括号初始化(意味着最外面的大括号指的是聚合初始化std::array,而第一个最内层大括号初始化其内部成员表示std::array是真正的C-Array).这将无法编译,因为std::pair<int, int>随后无法初始化1(所有大括号都已用完).clang会给出一个编译器错误,指出:

    error: no viable conversion from 'int' to 'std::pair<int, int>'
     std::array<std::pair<int, int>, 3> a{{1, 11}, {2, 22}, {3, 33}};
                                              ^
    
    Run Code Online (Sandbox Code Playgroud)

    另请注意,如果没有要初始化的内部成员聚合,即此问题得以解决

    std::pair<int, int> b[3] = {{1, 11}, {2, 22}, {3, 33}};
    
    Run Code Online (Sandbox Code Playgroud)

    将作为聚合初始化编译得很好.

  2. (你的意思是它.)你执行大括号删除初始化,因此最里面的大括号用于各个对的聚合初始化,而内部数组表示的大括号被省略.请注意,即使没有这种歧义,正如在rustx的答案中正确指出的那样,大括号的规则也不适用,因为std::pair没有聚合类型,所以程序仍然是不正确的.

编译器更喜欢选项1.通过提供额外的大括号,您可以执行全括号初始化并解除任何语法歧义.

  • @xskxzr您的示例显然无法解释为全括号聚合初始化,因为您只提供了一对大括号.模糊性取决于内括号的含义,而这里并不存在.所以在这种情况下,这只能是支持初始化. (3认同)

rus*_*tyx 14

C++ 14 大括号省略规则仅适用于子聚合初始化.

所以例如这样的工作:

std::array<std::array<int, 3>, 3> a{1, 11, 2, 22, 3, 33};
Run Code Online (Sandbox Code Playgroud)

在这里,聚合的聚合可以在没有额外括号的情况下进行列表初始化.

std::pair它不是聚合(它有构造函数),因此该规则不适用.

这意味着如果没有大括号省略规则,std::array本身就是一个内部有数组的聚合,需要一组额外的大括号才能进行列表初始化.请记住,类模板array实现为:

template<typename T, std::size_t N> 
struct array {
  T elems[N];
};
Run Code Online (Sandbox Code Playgroud)

要在没有大括号省略规则的情况下对列表进行初始化,您需要一组额外的大括号才能获得该elems成员.


and*_*eee 8

如果没有双括号,那么这个陈述就是含糊不清的.请考虑以下代码:

    std::array<std::pair<int, int>, 1> a = {{ {1, 2} }};
    std::array<int, 2> b = { {1, 2} };
Run Code Online (Sandbox Code Playgroud)

如果没有第一个定义双括号,编译器会将{ {1,2} }作为一个标量初始化列表array<int, 2>.您需要声明一个显式嵌套的braced-init-list,以便编译器识别内部列表也是聚合初始化的(与标量初始化相比),这样它就可以构造一个数组std::pair.