【问题标题】:C++ Default constructors in union with variant member with non-trivial default constructorC++ 默认构造函数与具有非平凡默认构造函数的变体成员联合
【发布时间】:2018-10-28 13:13:06
【问题描述】:

我最近阅读了关于联合默认构造函数的描述: Default Constructor

有如下规则:

块引用 删除了隐式声明的默认构造函数: [...] T 是一个联合,其中至少有一个变体成员具有非平凡的默认构造函数,并且 T 的任何变体成员都没有默认成员初始化器。[...]

然后我决定做一个练习并验证规则。

struct Member {
 public:
  // Member() : mX(0) {}
  virtual int GetX() {
    return mX;
  }
  int mX;
};

union DefaultConstructor {
  int mA;
  Member mMember;
  int GetA();
};

使用 gcc v5.3.1(我知道它已经很老了)我收到了预期的错误:

> ../src/DefaultConstrcutors.cpp: In function ‘void
> Test_DefaultConstructors()’: ../src/DefaultConstrcutors.cpp:26:22:
> error: use of deleted function
> ‘DefaultConstructor::DefaultConstructor()’    DefaultConstructor foo;
>                       ^ In file included from ../src/DefaultConstrcutors.cpp:19:0:
> ../src/DefaultConstructors.h:155:7: note:
> ‘DefaultConstructor::DefaultConstructor()’ is implicitly deleted
> because the default definition would be ill-formed:  union
> DefaultConstructor {
>        ^ ../src/DefaultConstructors.h:157:10: error: union member ‘DefaultConstructor::mMember’ with non-trivial ‘Member::Member()’   
> Member mMember;
>           ^

好的,所以根据规则,如果我为变体成员提供默认成员初始化程序,那么它应该可以编译。所以我将联合定义更改为:

union DefaultConstructor {
      int mA = 0;
      Member mMember;
      int GetA();
    };

现在它应该可以编译了,但我收到了同样的错误。

下一步是为 mMember 而不是 mA 提供默认初始化程序(只有一个联合变体成员可能有默认初始化程序)。

union DefaultConstructor {
      int mA;
      Member mMember{};
      int GetA();
    };

现在它可以编译了。

问题是:为什么它没有在第二种情况下编译,当 mA 有默认初始化程序时?根据上述规则,应该是可以的。这里提供了更多类似的规则:Union declaration

如果联合包含具有非平凡数据成员的非静态数据成员 默认构造函数,union的默认构造函数被删除 默认情况下,除非联合的变体成员具有默认成员 初始化器。

有人知道为什么它不起作用吗?

您好, 彼得

【问题讨论】:

    标签: c++ c++11 language-lawyer unions default-constructor


    【解决方案1】:

    cppreference 通常是一个很好的信息源,但这里的编译器是正确的。 C++11 的 n3337 草案在 9.5 联合 [class.union] 中包含一个非规范但明确的说明:

    如果联合的任何非静态数据成员具有非平凡的默认值 构造函数 (12.1)、复制构造函数 (12.8)、移动构造函数 (12.8)、复制赋值运算符 (12.8)、移动 赋值运算符(12.8)或析构函数(12.4),联合的相应成员函数必须是 用户提供,否则会为联合隐式删除(8.4.3)。

    没有提到一个成员有一个默认成员初始化器的情况是不会的。

    相同的注释仍然存在于 C++14 的草案 n4296 中,所以我认为它在实际的 C++ 标准中应该仍然相同。注释当然是非规范性的,但它们的目的是更清楚地解释标准,所以我认为 cppreference 的解释是错误的,因为它不尊重该注释,而 gcc 的解释是正确的。

    【讨论】:

    猜你喜欢
    • 2022-01-08
    • 2010-10-30
    • 1970-01-01
    • 2016-08-08
    • 1970-01-01
    • 2015-08-10
    • 1970-01-01
    • 1970-01-01
    • 2014-05-15
    相关资源
    最近更新 更多