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

时间:2014-10-26 10:59:19

标签: c++ constructor unions

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

  

如果union 的任何非静态数据成员具有非平凡的默认值   构造函数(12.1),复制构造函数(12.8),移动构造函数(12.8),   复制赋值运算符(12.8),移动赋值运算符(12.8)或   析构函数(12.4),union的相应成员函数必须   是用户提供的,或者它将被隐式删除(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()
{

}

DEMO

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

  

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

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

2 个答案:

答案 0 :(得分:7)

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

  

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

     

[...]

     
      
  • X是一个类似联合的类,其变体成员具有非平凡的默认构造函数,
  •   
     

[...]

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

[...]

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

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

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

答案 1 :(得分:2)

在您的示例中,问题不在于您的代码没有非平凡的defautl构造函数,而是它具有复制构造函数。

但通常情况下,union有几个成员:&#34; 最多一个非静态数据成员可以随时处于活动状态,即最多其中一个非静态数据成员可以随时存储在一个联合中&#34; (9.5 / 1)。

假设你有一个带有几个成员的联合,其中一些成员具有非平凡的构造函数或复制构造函数:

union W {
    A a; 
    int i; 
};

何时创建对象:

W w;  

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

这就是为什么你的联盟有一个删除的默认构造函数(在你的情况下是复制构造函数)的标准。用户提供缺少的默认功能应该足够了。

union W
{
    int i;
    A a;
    W() { /*...*/ }
    W(const W&c) { /*...*/ }
};

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

重要提示: 不幸的是,MSVC13不支持不受限制的联合:它仍然不接受任何具有任何非平凡默认功能的成员用户自定义。 GCC接受since 4.6和clang since 3.1