如果只有一个成员没有一个,那么为什么联合会有一个删除的默认构造函数呢?

13 c++ constructor unions

N3797::9.5/2 [class.union] 说:

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

我试图通过例子来理解这个说明:

#include <iostream>
#include <limits>

struct A
{
    A(const A&){ std::cout << "~A()" << std::endl; } //A has no default constructor
};

union U
{
    A a;
};

U u; //error: call to implicitly-deleted default constructor of 'U'

int main()
{

}
Run Code Online (Sandbox Code Playgroud)

DEMO

这种行为对我来说并不十分清楚.struct A没有隐式声明的默认构造函数,因为12.1/4: [class.ctor]说:

如果类X没有用户声明的构造函数,则没有参数的构造函数被隐式声明为默认值(8.4).

这意味着struct A没有非平凡的默认构造函数(根本没有默认构造函数,特别是非平凡的).那union U不必有一个删除的默认构造函数.怎么了?

小智 7

相关的措辞在C++ 11 [class.ctor] p5(强调我的):

类的默认构造函数是类X的构造函数X,可以在没有参数的情况下调用.如果类没有用户声明的构造X函数,则没有参数的构造函数被隐式声明为默认值(8.4).[...] 如果出现以下情况,X则默认的类默认构造函数被定义为已删除:

[...]

  • X 是一个类似于union的类,它有一个带有非平凡构造函数的变量成员,

[...]

  • 任何直接或虚拟基类,或没有大括号或等号初始值的非静态数据成员,都有类类型M(或其数组),M 并且没有应用于M默认构造函数的默认构造函数或重载决策(13.3)导致歧义或在默认默认构造函数中删除或无法访问的函数中,或者

[...]

您的类A没有默认构造函数,因此X包含非A初始化类型的非静态数据成员的类(无论是union还是非union)的默认默认构造函数(无论是隐式还是非显式)会导致默认构造函数X被删除.它必须:编译器根本无法生成任何其他默认构造函数.

至于你在评论中的后续问题:

如果不是A 没有默认构造函数,它有一个非平凡的默认构造函数,那么在union和non-union类中使用它有区别,这也是[class.ctor] p5的一部分:这是我在前面的引文中没有强调的第一个要点.


Chr*_*phe 5

在您的示例中,问题不在于您的代码没有重要的默认构造函数,而在于它有一个复制构造函数。

但一般情况下,aunion有几个成员:“任何时候最多有一个非静态数据成员可以是活动的,也就是说,任何时候最多可以有一个非静态数据成员的值存储在联合体中。时间”(9.5/1)。

假设您有一个包含多个成员的联合,其中一些成员具有重要的构造函数或复制构造函数:

union W {
    A a; 
    int i; 
};
Run Code Online (Sandbox Code Playgroud)

当你创建一个对象时:

W w;  
Run Code Online (Sandbox Code Playgroud)

这个对象应该如何默认构造?哪一位成员应该是活跃成员?这样的对象应该如何默认复制?是应该构建/复制的A还是 the ?int

这就是为什么标准假定您的联合具有已删除的默认构造函数(在您的情况下是复制构造函数)。用户提供缺少的默认函数就足够了。

union W
{
    int i;
    A a;
    W() { /*...*/ }
    W(const W&c) { /*...*/ }
};
Run Code Online (Sandbox Code Playgroud)

本文详细解释了 C++11 关于该主题的基本原理和措辞。

重要提示:不幸的是, MSVC13不支持无限制联合:它仍然不接受任何具有用户定义的非平凡默认函数的任何成员。GCC从 4.6 开始接受它,从 3.1 开始接受 clang。