我应该如何大括号初始化 std::pairs 的 std::array?

Posted

技术标签:

【中文标题】我应该如何大括号初始化 std::pairs 的 std::array?【英文标题】:How should I brace-initialize an std::array of std::pairs? 【发布时间】:2015-02-24 11:28:48 【问题描述】:
std::array<std::pair<int, int>, 2> ids =   0, 1 ,  1, 2  ;

VS2013 错误:

error C2440: 'initializing' : cannot convert from 'int' to 'std::pair' 没有构造函数可以采用源类型,或者构造函数重载决议不明确`

我做错了什么?

【问题讨论】:

【参考方案1】:

添加另一对大括号。

std::array<std::pair<int, int>, 2> ids =    0, 1 ,  1, 2   ;

std::array&lt;T, N&gt; 是一个包含T[N] 类型成员的聚合类。通常,您可以像初始化一个普通的 T[N] 数组一样初始化,但是当您处理非聚合元素类型时,您可能需要更加明确。

【讨论】:

这似乎可以解释一切,直到您使用 std::make_pair 查看 Joachim 的答案。 that 是如何工作的,没有额外的一对大括号? @TonyK 一般来说,大括号可以省略。 int a[2][2] = 0, 1, 2, 3 ; 完全有效。但是当您使用用户提供的构造函数处理类时,事情会变得有些棘手: 0, 1 可能是尝试初始化第一个元素或第一个子元素。歧义得到解决,有利于第一个元素。另一方面,make_pair 的结果只能用于初始化第一个子元素。 标准保证工作的唯一事情是 "array&lt;T, N&gt; a = initializer-list ; 其中 initializer-list 是一个逗号分隔的列表,最多包含 N 元素,其类型可转换为T"。额外的一对大括号可能适用于所有当前的实现,但不能保证。 @T.C.反正还没有。关于数组有几个相关的未解决问题。一是array&lt;T, N&gt; 应该与T[N] 布局兼容。另一个是标准对std::array 的描述中的成员T elems[N]; 被注释为“仅用于说明”,并不打算像[objects.within.classes]p2 所说的那样工作。出于实际目的,这个答案是正确的。严格阅读标准不支持这个答案,但确实支持标准完全错误的立场,目前还不能从中得出有意义的结论。 :) 如果数组包含三对,这里的建议不起作用:std::array&lt;std::pair&lt;int, int&gt;, 3&gt; ids = 0, 1 , 1, 2 , 2, 3 ; 无法编译。但是,忽略 = 会有所帮助:std::array&lt;std::pair&lt;int, int&gt;, 3&gt; ids 0, 1 , 1, 2 , 2, 3 ; 编译时不会出现错误。我花了很长时间才弄清楚这一点。也许应该编辑答案,以便警告未来的访问者?另外,我自己提出了一个额外的问题:为什么会这样?【参考方案2】:

std::array 是一个聚合。它只有一个数据成员——std::array 特化的指定类型的数组。根据 C++ 标准。 (8.5.1 聚合)

2 当聚合由初始化列表初始化时,如 在 8.5.4 中指定,初始化列表的元素被视为 聚合成员的初始化器,增加下标 或会员订单

所以这条记录

std::array<std::pair<int, int>, 2> ids =   0, 1 ,  1, 2  ;

有更多的初始化器然后在 std::array 中有数据成员。

std::array 的数据成员又是一个聚合。您必须为其提供一个初始化列表。

所以记录看起来像

std::array<std::pair<int, int>, 2> ids =    0, 1 ,  1, 2   ;

为了更清楚,您可以通过以下方式想象初始化

std::array<std::pair<int, int>, 2> ids =  /* an initializer for data member of the array */ ;

由于数据成员是聚合的,所以你必须写

std::array<std::pair<int, int>, 2> ids =   /* initializers for the aggregate data member*/  ;

最后

std::array<std::pair<int, int>, 2> ids =    0, 1 ,  1, 2   ;

【讨论】:

如果你按照标准,那么不能保证std::array只有一个数据成员。 @T.C.如果没有此信息,您将无法正确初始化数组。至少为了说明,该标准在数组定义中包括以下数据成员 Telems[N]; 标准保证 array&lt;T, N&gt; a = initializer-list ; 在初始化列表最多有 N 个元素且每个元素都可以转换为 T 的情况下工作。无法保证内置数组(如果使用一个 - 我不知道不使用一个是否可以满足所有要求)是唯一的数据成员。 @T.C.我也不知道有什么可以代替数组。如果能明确地写出内部表示是一个数组,似乎会更好。

以上是关于我应该如何大括号初始化 std::pairs 的 std::array?的主要内容,如果未能解决你的问题,请参考以下文章

如何修复警告:初始化程序周围缺少大括号?

何时使用大括号封闭的初始化程序?

大括号封闭初始化列表?转换为矢量

大括号封闭的初始化列表构造函数

数组必须用大括号括起来的初始化程序 c++ 初始化

从朋友类继承时无法使用大括号括起来的初始化列表