【问题标题】:How to use designated initialization of derived aggregates in C++?如何在 C++ 中使用派生聚合的指定初始化?
【发布时间】:2021-08-07 19:25:22
【问题描述】:

我有一个聚合结构 B 派生自另一个聚合 A。我想初始化它,有两种选择:普通聚合初始化和C++20指定初始化器:

struct A {};
struct B : A { int x; };

int main() {
    [[maybe_unused]] B x{{},1}; //ok everywhere
    [[maybe_unused]] B y{.x=1}; //warning in GCC
}

普通的初始化{{},1} 工作正常,但在这种情况下看起来太笨拙了,因为父聚合有额外的{}

在我看来,指定的初始化器 {.x=1} 看起来更好,但它们在 GCC 中会产生一个奇怪的警告:

warning: missing initializer for member 'B::<anonymous>' [-Wmissing-field-initializers]
    6 |     [[maybe_unused]] B y{.x=1}; //warning in GCC
      |                              ^

演示:https://gcc.godbolt.org/z/8jEYY16c6

有没有办法在这里使用指定的初始化器,同时让GCC冷静下来,消除警告?

【问题讨论】:

  • 在 MSVC 中对于指定的初始化程序也看不到这个警告(那是 /W4 和我喜欢启用的许多其他开关......
  • 看起来像一个 GCC 错误 stackoverflow.com/questions/49081541 该目标是针对 C 的,但我认为 GCC 对 C++20 指定的初始值设定项使用相同的机制,因此会发出警告。

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


【解决方案1】:

有没有办法在这里使用指定的初始化器,同时让GCC冷静下来,消除警告?

没有。 GCC 的警告是正确的:您缺少基类 A 的初始化程序。现在,在这种情况下,您碰巧想从 = {} 初始化(当您不提供初始化程序时会发生这种情况),这是您可以初始化它的唯一方法,所以也许在这种特定情况下,警告有点愚蠢(但在基类实际上有成员的一般情况下,这是完全合理的)。此外,警告可能更有用,实际上会告诉您您缺少哪个成员的初始化程序...

不幸的是,没有办法在 designated-initializer-list 中实际命名基类,这意味着无法使用指定来实际初始化 B初始化器。

有一个解决此问题的提案 (P2287),其目的是允许 B{.A={}, .x=1},但这仍在进行中。

【讨论】:

  • en.cppreference.com/w/cpp/language/aggregate_initialization看来A的初始化器可以跳过,它会被聚合初始化,就好像它是用= {}初始化的一样。我错过了什么?
  • @cigien 是的,这就是为什么跳过初始化程序的警告 - 不是错误。
  • 哦,我明白了。我把这个问题读成询问代码是否有效,但如果是的话,OP似乎想摆脱警告。
【解决方案2】:

您的代码是有效的,并且警告是正确的;你缺少一个初始化器,它将被聚合初始化。

您可以使用标志 -Wno-missing-field-initializers 禁用警告。

demo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-24
    • 2021-10-23
    • 2020-10-22
    • 1970-01-01
    • 2020-08-19
    • 1970-01-01
    • 2021-03-25
    相关资源
    最近更新 更多