二维列表初始化std::array

List initialisation of two dimensional std::array

在下面的程序中,我尝试使用具有嵌套列表初始化的行(当前已注释掉)来初始化我的 2x2 元素 std::array。 MSVC2017 给了我 "too many initializers" 的编译器错误。为什么?

然后我试了一下非嵌套列表初始化,结果成功了。为什么?

这似乎与嵌套 std::vector 的初始化不一致。参见 main() 的第三行。请问这是怎么回事?

#include <array>
#include <iostream>
#include <vector>

int main()
{
    //std::array<std::array<int,2>,2> x = {{0,1},{2,3}};    // ERROR: TOO MANY INITIALIZERS
    std::array<std::array<int,2>,2> x = {0,1,2,3};          // OK
    std::vector<std::vector<int>> y = {{0,1},{2,3}};        // ALSO OK: NOT TOO MANY INITIALIZERS IF A std::vector?
}

std::array有点特殊。它通常作为内置数组的包装器实现。那么对于aggregate initialization,还需要再添加一对{},如

std::array<std::array<int,2>,2> x = {{{0,1},{2,3}}};

另一方面,std::array<std::array<int,2>,2> x = {0,1,2,3}; 有效是因为 brace elision

If the aggregate initialization uses copy-list-initialization syntax (T a = {args..}), (until C++14)the braces around the nested initializer lists may be elided (omitted), in which case as many initializer clauses as necessary are used to initialize every member or element of the corresponding subaggregate, and the subsequent initializer clauses are used to initialize the following members of the object.

如果指定了嵌套的初始化列表,则必须在正确的层中指定初始化列表。对于这种情况,它应该是 3 层。

在此声明中

std::array<std::array<int,2>,2> x = {{0,1},{2,3}};

您有三个嵌套聚合。第一对用大括号括起来的值

{0,1}

被编译器视为第二个聚合的初始值设定项,它作为一个子聚合出现在声明中。所以大括号中的第二对值

{2,3}

被编译器认为是没有对应对象的冗余。

你可以声明数组,例如

std::array<std::array<int, 2>, 2> x = { { {0,1},{2,3} } };

聚合初始化时大括号可能会被省略。 (C++17 标准,11.6.1 聚合)

12 Braces can be elided in an initializer-list as follows. If the initializer-list begins with a left brace, then the succeeding comma-separated list of initializer-clauses initializes the elements of a subaggregate; it is erroneous for there to be more initializer-clauses than elements. If, however, the initializer-list for a subaggregate does not begin with a left brace, then only enough initializer-clauses from the list are taken to initialize the elements of the subaggregate; any remaining initializer-clauses are left to initialize the next element of the aggregate of which the current subaggregate is an element.

所以在这个声明中

std::array<std::array<int,2>,2> x = {0,1,2,3};

大括号被省略,聚合被初始化,正如引用中描述的那样..

在此声明中

std::vector<std::vector<int>> y = {{0,1},{2,3}};

使用了 class std::vector 的构造函数,它接受 std::initializer_list 作为参数。在这种情况下,构造函数构建与初始化列表中的元素一样多的向量元素。