【问题标题】:Double braces required for list-initialization of container std::array容器 std::array 的列表初始化需要双括号
【发布时间】:2020-11-22 12:34:50
【问题描述】:

用户定义类型的容器的列表初始化并不像我预期的那样运行。 看到这个sn-p:

#include <array>

struct A {
    char C;
    int s;
};

int main(int argc, char * argv[]) {
    A x = {'x'}, y = {'y'};

    std::array<int, 2> i = {1, 2}; // Ok

    std::array<A, 2> a = {x, y}; // Ok
    //std::array<A, 2> b =  { {'x',1000}, {'y',2000} }; // Error: too many initializers!!!
    std::array<A, 2> c = { A{'x',1000}, A{'y',1000} };
    std::array<A, 2> d = {{ {'x',1000}, {'y',1000} }}; // Ok!!
    std::array<A, 2> e = {'x', 2000, 'y', 5000}; // Ok!!
} 

我可以初始化i,就好像它是一个基本数组一样。我可以对 a 做同样的事情,只要它们是变量。但是如果不指定A的类型就无法初始化b,比如c

  1. 要初始化std::array 而不明确说明A 的类型,我必须添加另一对大括号。需要双括号背后的逻辑是什么?为什么不能像b那样用一对大括号包围列表来初始化它?

  2. 另外,令人惊讶的是c 有效,它只产生两个对象!直观地说,我希望 e 会产生错误,因为最多 2 个对象有 4 个初始值,但编译器会正确填写 A 的成员!为什么会这样?

【问题讨论】:

  • 这个answer 解决了一个类似于 1) 的问题,但是 2) 没有得到回答。

标签: c++ curly-braces stdarray list-initialization


【解决方案1】:

大括号,无论嵌套多么深,都会在考虑任何类型信息之前与正在初始化的对象的结构相匹配。由于std::array&lt;T,N&gt; 必须包含一个真正的T[N](而不是一个),因此结构是array 内部有一个对象,即大批。因此,使用两个左大括号来开始该数组的初始化程序,如果需要整个嵌套集来初始化一个数组元素,或者如果存在多个这样的嵌套集,则该初始化器不起作用。

当一些初始化子句是一个表达式,即使是A{…},这种分解停止并且初始化器用于一个子对象。但是,如果该表达式无法转换为相应子对象的类型,并且该类型本身是一个聚合,则 大括号省略 发生,随后的初始化器将用于 子对象尽管没有牙套。当这适用于 T[N] 对象本身时,array 可以仅使用一层大括号进行初始化。

因此,简而言之,无论是否有效,左大括号都会导致聚合分解,但类型不匹配也会导致聚合分解。

【讨论】:

    猜你喜欢
    • 2021-07-14
    • 2018-04-20
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    • 2016-04-14
    • 2017-07-24
    • 2020-05-14
    • 1970-01-01
    相关资源
    最近更新 更多