【发布时间】:2016-01-03 20:43:35
【问题描述】:
我试图了解 C++11 是如何扩展联合的。改变的一件事是现在能够使用具有非平凡特殊成员函数的非静态数据成员。来自cppreference.com
如果联合包含具有非平凡特殊成员函数(默认构造函数、复制/移动构造函数、复制/移动赋值或析构函数)的非静态数据成员,则默认情况下该函数在联合中被删除并需要由程序员明确定义。 最多一个数据成员可以有一个默认的成员初始化器。
我正在尝试以下代码:
struct X
{
~X() {};
};
union U
{
X x;
~U() {};
};
int main()
{
U s1{}; // works, probably aggregate initialization
U s2; // DOES NOT compile, why?
}
这里X(用作联合的数据成员)有一个用户提供的析构函数,因此联合的析构函数默认被删除。因此,我明确提供了一个。但是代码编译失败,报错
注意:'U::U()' 被隐式删除,因为默认定义格式不正确:
如果我删除最后一行U s2;,代码将编译。
问题这是怎么回事?为什么U s1{}; 编译,但U s2; 不编译?联合的默认 ctor 是否标记为已删除(如果是,为什么?!),在第一种情况下,我们只是聚合初始化?请注意,如果我提供U(){}; // not U() = default;,则代码会编译(但如果我只提供X 的ctor,则不会)。
编辑
深挖标准(N4527)后:
工会:9.5/2 [class.union]
[注意:如果联合的任何非静态数据成员具有非平凡的默认构造函数 (12.1)、复制构造函数 (12.8)、移动构造函数 (12.8)、复制赋值运算符 (12.8)、移动赋值运算符 ( 12.8)或析构函数(12.4),联合的相应成员函数必须是用户提供的,否则它将为联合隐式删除(8.4.3)。 ——尾注]
这似乎是一个 gcc 错误(现已报告 here)。该代码在 clang 和 gcc 4.8.2 或更早版本上编译,它在 gcc4.9 及更高版本上中断(感谢@T.C. 指出)。
编译器:g++5.3,-std=c++11 使用。
【问题讨论】:
标签: c++ c++11 language-lawyer unions