std::array的聚合初始化需要大量令人困惑的花括号。

8

I have the following code:

   enum class MessageDeliveryMethod
   {
      POST_MASTER,
      BUBBLE,

      NUM_ENUMERATORS
   };

   namespace
   {
      using MapType = std::array<
         std::pair<char const*, MessageDeliveryMethod>,
         static_cast<std::size_t>(MessageDeliveryMethod::NUM_ENUMERATORS)
      >;

      MapType g_mapping = {{
         {"POST_MASTER", MessageDeliveryMethod::POST_MASTER},
         {"BUBBLE", MessageDeliveryMethod::BUBBLE},
      }};
   }

这段代码可以编译通过,但我不知道为什么。变量 g_mapping 需要多出一层看似冗余的花括号。换句话说,我预期初始化应该像这样:
MapType g_mapping = {
   {"POST_MASTER", MessageDeliveryMethod::POST_MASTER},
   {"BUBBLE", MessageDeliveryMethod::BUBBLE},
};

(移除一层外部括号)。

据我了解,在 C++14 之前,进行直接初始化需要额外的一层括号。然而,根据这个页面(看那里的例子),不应要求进行复制初始化。

有人能够解释一下吗?

更新:

这个 SO 问题 被认为与我的问题重复,确实回答了一些特定和有用的问题(与我的问题相关),但在上下文之外,我的问题由于使用了 pair(最初我以为是导致问题的原因)而变得令人困惑。我永远不会首先找到那个 SO 问题,所以如果有什么值得的话,我认为我提出问题的方式可能会帮助人们从不同的角度得出解决方案。


标题为Plusone。花括号省略真的是一种...反括号? - Kerrek SB
我已经编辑了我的帖子,以澄清为什么我不认为它是重复的。最近,SO的管理员/社区在考虑其他人的观点之前过早地关闭问题,将其视为重复问题,这一点非常糟糕。 - void.pointer
保留网站上重复的问题是为了从不同角度进行讨论。这并不意味着已有答案存在是个问题。 - Bill Woodger
3个回答

7
std::array是一个结构体,其中包含一个数组。
因此,第一对大括号用于初始化作为该数组的结构体的数据成员。 第二对大括号用于初始化结构体内部的数组。 第三对大括号用于初始化每个std :: pair类型的对象。
更准确地说,根据C ++标准(23.3.2.1类模板数组概述):
2.数组是一个聚合体(8.5.1),可以使用以下语法进行初始化。
array<T, N> a = { initializer-list }; 

其中initializer-list是最多包含N个元素的逗号分隔列表, 其类型可转换为T。


谢谢,这很有道理。看起来这是std::array的设计问题。我建议可以通过为std::initializer_list提供构造函数重载来解决,但那样会使它成为非聚合类型,而这是必须的。不确定解决方案是什么,但现在使用起来有些尴尬。 - void.pointer

2

std::array 是一个嵌套的聚合类型 - 一个只包含数组成员的类。在 C++14 之前,需要使用两层大括号进行聚合初始化:一层用于包围类成员列表(其中只有一个成员即数组),另一层用于包围数组元素列表。如果您想要对每个数组元素进行列表初始化,则需要第三层大括号,就像这里所示。

C++14 允许您在初始化嵌套聚合类型时“扁平化”列表,如您链接的页面所述。


std::pair 不是一个聚合体。 - user3920237
1
@remyabel:不是这样的;但它仍然可以进行列表初始化。我是在描述为什么需要外部两层大括号,而不是每个“pair”初始化器周围的大括号。 - Mike Seymour
在std::array中有很多需要两组大括号的重复项,但在这种特定的情况下,您不能省略任何大括号。 - user3920237
@remyabel:你可以用其他形式的初始化替换每对周围的那些“ones”。我不太确定你想表达什么意思;我的理解是这个问题问的是外面两对。如果你宁愿让我找到一个重复的问题而不是直接回答问题,那我很抱歉。 - Mike Seymour
我所说的重复评论是指这个问题似乎不同,因为它涉及到非聚合类型,因此答案应该相应地不同。 - user3920237
@remyabel:好的。我已经添加了一条注释,第三级是对每个数组成员进行列表初始化。 - Mike Seymour

0

在标准中,我们有23.3.2.1(3)

数组是一个聚合体(8.5.1),可以使用以下语法进行初始化:

array<T, N> a = { initializer-list };

这表明当您使用内部化列表初始化数组时,需要将其包装在花括号中。


2
其中 initializer-list 是最多包含 N 个可转换为 T 类型的逗号分隔元素列表。 - T.C.

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