Union的默认构造函数被隐式删除

Den*_*kov 27 c++ language-lawyer

下面的代码:

struct non_trivially {
    non_trivially() {};
};

union U {
    bool dummy{false};
    non_trivially value;
};

int main() {
    U tmp;
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/1cMsqq9ee

在 clang (13.0.0) 上产生下一个编译器错误:

source>:11:7: error: call to implicitly-deleted default constructor of 'U'
    U tmp;
      ^ <source>:7:19: note: default constructor of 'U' is implicitly deleted because variant field 'value' has a non-trivial default constructor
    non_trivially value;
Run Code Online (Sandbox Code Playgroud)

但使用 MSVC (19.30) 成功编译。

根据 cppreference 它应该是一个有效的代码:https ://en.cppreference.com/w/cpp/language/union

如果联合体包含具有非平凡默认构造函数的非静态数据成员,则默认情况下将删除联合体的默认构造函数,除非联合体的变体成员具有默认成员初始值设定项。

在我的示例中,U 中有一个带有默认成员初始值设定项的替代方案,因此不应删除默认构造函数,但确实如此。我缺少什么?

Art*_*yer 22

这是CWG2084。如果您提供默认成员初始值设定项,则 Clang 和 gcc 在删除默认构造函数时是错误的。

采用更改后添加到标准中的相关引用(在 [class.default.ctor] 中):

如果满足以下条件,则类 X 的默认构造函数被定义为已删除:

  • X 是一个联合体,它有一个带非平凡默认构造函数的变体成员,并且 X 的所有变体成员都没有默认成员初始值设定项,
  • [...]
  • X 是一个联合体,其所有变体成员都是 const 限定类型(或其数组),

(作为唯一引用联合类型的两点,两者都不适用,因此不应隐式删除它)

解决方法是用户提供一个构造函数:

union U {
    constexpr U() : dummy{false} {}
    bool dummy;
    non_trivially value;
};

// Or this also seems to work
union U {
    constexpr U() {}
    bool dummy{false};
    non_trivially value;
};
Run Code Online (Sandbox Code Playgroud)

  • 这是一个比我的答案**多**好的答案,WD。 (2认同)

Den*_*kov 1

最后在 clang-17 中修复: https: //godbolt.org/z/97rqexTxE