std::array 结构初始化器列表语法

Reg*_*gus 0 c++ stdarray

考虑以下 C++ 代码:

struct My_Struct
{
  int a;
  int b;
};
Run Code Online (Sandbox Code Playgroud)

现在我想声明这些结构的常量 std::array :

选项A:

const std::array<My_Struct,2> my_array =
{
  {1,2},
  {2,3}
};
Run Code Online (Sandbox Code Playgroud)

选项B:

const std::array<My_Struct,2> my_array =
{
  My_Struct(1,2),
  My_Struct(2,3)
};
Run Code Online (Sandbox Code Playgroud)

问题:为什么选项A无法编译而只有选项B可以编译?初始化 std::array 时嵌套花括号有什么问题?

在我看来,编译器应该拥有成功编译选项 A 所需的所有信息,但它会产生“太多初始值设定项值”错误。

同时,嵌套花括号在初始化普通数组时效果非常好:

const My_Struct my_array[] =
{
      {1,2},
      {2,3}
};
Run Code Online (Sandbox Code Playgroud)

编译器是MSVC 17.2,C++20模式。

我可以接受选项 B,但我想了解在 C++ 知识方面我在选项 A 中到底无法理解什么。

Mil*_*nek 9

std::array是一个包含实际数组的类。它看起来像这样:

\n
template <typename T, size_t N>\nstruct array\n{\n    T _unspecified_name[N];\n\n    // Member functions.\n};\n
Run Code Online (Sandbox Code Playgroud)\n

注意std::array没有构造函数或私有数据成员,因此它是一个聚合。

\n

当你用大括号初始化一个std::array你正在对一个类进行聚合初始化,其中一个成员本身就是一个聚合。通常这需要两组大括号:

\n
//                       Braces for std::array\n//                       \xe2\x94\x82        \xe2\x94\x82\n//                       \xe2\x96\xbc        \xe2\x96\xbc\nstd::array<int, 2> arr = { {1, 2} };\n//                         \xe2\x96\xb2    \xe2\x96\xb2\n//                         \xe2\x94\x82    \xe2\x94\x82\n//                         Braces for int[2] member\n
Run Code Online (Sandbox Code Playgroud)\n

C++ 有大括号省略规则来使这种情况变得更好。您可以省略内部大括号集,初始化器将“传递”到本身是聚合的底层成员对象。在本例中,它是 的std::array成员int[2]

\n

这是你问题的根源。当您初始化使用大括号的数组时My_Struct,编译器认为您打算使用内部大括号集来初始化std::array'sMy_Struct[]成员而不是My_Struct内部成员。由于有两个初始化器,而它只期望一个初始化器,因此会抛出错误:

\n
//                                  Initializer for std::array\n//                                  \xe2\x94\x82                \xe2\x94\x82\n//                                  \xe2\x96\xbc                \xe2\x96\xbc\nstd::array<My_Struct, 2> my_array = { {1, 2}, {2, 3} };\n//                                    \xe2\x96\xb2    \xe2\x96\xb2  \xe2\x96\xb2    \xe2\x96\xb2\n//                                    \xe2\x94\x82    \xe2\x94\x82  \xe2\x94\x82    \xe2\x94\x82\n//      Initializer for unnamed My_Struct[2]  \xe2\x94\x82    \xe2\x94\x82\n//                                            What is this initializer for? I only have one member to initialize\n
Run Code Online (Sandbox Code Playgroud)\n

为了避免这种情况,你只需要添加另一组大括号:

\n
//                                  \xe2\x94\x8c Initializer for std::array \xe2\x94\x90\n//                                  \xe2\x94\x82                            \xe2\x94\x82\n//                                  \xe2\x96\xbc                            \xe2\x96\xbc\nstd::array<My_Struct, 2> my_array = { {     {1, 2}, {2, 3}     } };\n//                                    \xe2\x96\xb2     \xe2\x96\xb2    \xe2\x96\xb2  \xe2\x96\xb2    \xe2\x96\xb2     \xe2\x96\xb2\n//                                    |     \xe2\x94\x82    \xe2\x94\x82  \xe2\x94\x82    \xe2\x94\x82     \xe2\x94\x82\n//                                    |     |Initializers\xe2\x94\x82     \xe2\x94\x82\n//                                    |   For array elements   \xe2\x94\x82\n//                                    |                        |\n//                               Initializer for unnamed My_Struct[2]\n
Run Code Online (Sandbox Code Playgroud)\n