【问题标题】:Does designated initializer of sub-aggregate require curly braces?子聚合的指定初始化器是否需要花括号?
【发布时间】:2021-10-11 16:27:38
【问题描述】:

在下面的程序中,聚合结构B 具有字段a,它本身就是一个聚合。是否可以使用 C++20 指定初始化器来设置其值而不用大括号括起来?

struct A { int i; };
struct B { A a; };

int main() { 
    [[maybe_unused]] B x{1}; //ok everywhere
    [[maybe_unused]] B y{.a = {1}}; //ok everywhere
    [[maybe_unused]] B z{.a = 1}; //ok in MSVC,Clang; error in GCC
}

MSVC 和 Clang 编译器接受此代码。但是 GCC 发出一个奇怪的错误:

error: 'A' has no non-static data member named 'a'

演示:https://gcc.godbolt.org/z/65j1sTcPG

这是 GCC 中的错误,还是标准不允许这种初始化?

【问题讨论】:

  • 这个错误看起来怪怪的,但我希望拒绝第三个是正确的。它看起来很像A a = 1;(我敢肯定他们都会拒绝)。
  • 也许它像B z {{.a = 1}};一样解析它?
  • @NateEldredge 这很有意义!

标签: c++ c++20 designated-initializer


【解决方案1】:

GCC reject 这段代码是正确的:它尝试从 1 ([dcl.init.aggr]/4.2) 复制初始化 z.a,正如 cmets 所说的那样不工作。然而,GCC 似乎设想产生诊断的大括号省略是无效的:对于指定的初始化器列表来说,它只是不存在。

【讨论】:

    【解决方案2】:

    TLDR; GCC 是对的,其他人都是错的,因为他们一直在假装指定的初始化程序列表就像等效的非指定初始化程序列表一样。


    要了解这里发生了什么(以及为什么编译器不同意),让我们看一下您的第一个示例:

    B x{1};
    

    由于我们使用大括号,rules of list initialization kick in.该列表不是指定的初始化器列表,因此 3.1 失败。 3.2 失败,因为int 不是B 类型或从B 派生的类型。 3.3 失败,因为B 不是字符数组。最后是 3.4,它把我们带到aggregate initialization

    [dcl.init.aggr]/3.2 tells usB 的显式初始化元素由B::a 组成。

    第 4 段告诉我们显式初始化的元素是如何初始化的。 4.1 不适用,因为B 不是union。但也... 4.2 不适用,因为B::a 不能从1 复制初始化。

    这似乎不应该工作。幸好paragraphs 15 and 16 exist

    可以在初始化列表中省略大括号,如下所示。如果初始化器列表以左大括号开头,则后续的初始化器子句的逗号分隔列表初始化子聚合的元素;初始化子句多于元素是错误的。但是,如果子聚合的初始化器列表不以左大括号开头,则仅从列表中获取足够的初始化器子句来初始化子聚合的元素;剩下的任何初始化子句都被留下来初始化聚合的下一个元素,当前子聚合是其中的一个元素。

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

    也就是说,如果初始化器无法通过复制初始化来初始化A,则使用大括号省略规则。并且A 可以{1} 的初始化器列表中初始化.因此,它是。

    这就是指定初始化器有问题的地方。 designated-initializer-list 不是 initializer-list。因此,大括号省略段落不适用

    因此,B z{.a = 1}; 必须失败。

    其他编译器没有捕捉到这一点的原因可能如下。他们可能通过剥离指定并在非连续元素之间插入任何默认成员初始化器/值初始化来实现指定初始化器,然后应用正常的聚合初始化器规则。但这并不完全相同,因为指定的初始化列表不参与括号省略。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-30
      • 1970-01-01
      • 2010-12-04
      • 1970-01-01
      • 1970-01-01
      • 2013-09-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多