std::array 初始化中的大括号省略

Posted

技术标签:

【中文标题】std::array 初始化中的大括号省略【英文标题】:Brace elision in std::array initialization 【发布时间】:2013-06-03 20:30:12 【问题描述】:

假设有一个std::array 被初始化。用双括号也没关系:

std::array<int, 2> x = 0, 1;
std::array<int, 2> x0, 1;

在旧的聚合初始化中使用单大括号也是可以的,因为大括号省略会处理丢失的大括号:

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

但是,可以使用带有单括号的列表初始化吗? GCC 接受它,Clang 以“在使用直接列表初始化时不能省略子对象初始化周围的大括号”来拒绝它。

std::array<int, 2> x0, 1;

标准中唯一提到大括号省略的部分是 8.5.1/12,它说:

在使用赋值表达式初始化聚合成员时,会考虑所有隐式类型转换(第 4 条)。如果赋值表达式可以初始化成员,则初始化该成员。否则,如果成员本身是子聚合,则假定大括号省略,并考虑使用赋值表达式来初始化子聚合的第一个成员。

8.5.1 是关于聚合初始化的,所以这应该意味着 Clang 拒绝是正确的,对吧?没那么快。 8.5.4/3 说:

类型 T 的对象或引用的列表初始化定义如下:

[…]

——否则,如果 T 是一个聚合,则执行聚合初始化 (8.5.1)。

我认为这意味着与聚合初始化完全相同的规则,包括大括号省略、应用,这意味着 GCC 可以正确接受。

我承认,措辞不是特别清楚。那么,哪个编译器在处理第三个 sn-p 时是正确的?大括号省略是否发生在列表初始化中,还是没有?

【问题讨论】:

好问题!可能值得一提的是您使用的是哪种标准。 C++11 标准,或者如果不是,哪个特定草案。 “类赋值初始化”称为复制初始化。它调用复制构造函数,而不是赋值运算符。 @TemplateRex:这就是我使用“喜欢”作品的原因。 @juanchopanza: n3290,与标准 IIRC 相同。 最好使用标准术语,人们会感到困惑,可能会认为您不理解并进行这样的对话:-) 【参考方案1】:

相关:http://en.cppreference.com/w/cpp/language/aggregate_initialization

总之,

struct S 
    int x;
    struct Foo 
        int i;
        int j;
        int a[3];
     b;
;
S s1 =  1,  2, 3, 4, 5, 6  ;
S s2 =  1, 2, 3, 4, 5, 6; // same, but with brace elision
S s31, 2, 3, 4, 5, 6  ; // same, using direct-list-initialization syntax
S s41, 2, 3, 4, 5, 6; // error in C++11: brace-elision only allowed with equals sign
                        // okay in C++14

【讨论】:

【参考方案2】:

大括号省略适用,但不适用于 C++11。在 C++14 中,它们将因为 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1270 而适用。如果幸运的话,Clang 会将其反向移植到他们的 C++11 模式(希望他们会这样做!)。

【讨论】:

到目前为止,archlinux 中的clang-5.0 仍然不支持大括号省略,即使使用-std=c++17

以上是关于std::array 初始化中的大括号省略的主要内容,如果未能解决你的问题,请参考以下文章

如何使用省略尾随 '\0' 的字符串文字初始化 std::array<char, N>

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

大括号之谜:C++的列表初始化语法解析

联合中的大括号或相等初始化器

基于范围的大括号初始化器而不是非常量值?

编译器生成的默认构造函数是否会将std :: array中的指针初始化为nullptr?