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

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

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

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

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

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

std::array<int, 2> x{0, 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 相同。
  • 最好使用标准术语,人们会感到困惑,可能会认为您不理解并进行这样的对话:-)

标签: c++ c++11 language-lawyer list-initialization aggregate-initialization


【解决方案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 s3{1, {2, 3, {4, 5, 6} } }; // same, using direct-list-initialization syntax
S s4{1, 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
    猜你喜欢
    • 1970-01-01
    • 2015-02-24
    • 1970-01-01
    • 1970-01-01
    • 2012-07-29
    • 2018-04-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多