我最近阅读了工会的默认构造函数的描述: 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的默认构造函数 默认情况下,除非union的变体成员具有默认成员 初始化器。
任何人都知道为什么它不起作用?
问候, 彼得
答案 0 :(得分:4)
cppreference通常是一个很好的信息源,但这里的编译器是正确的。草案n3337 for C ++ 11包含9.5 Unions [class.union]一个非规范但明确的说明:
如果union的任何非静态数据成员具有非平凡的默认值 构造函数(12.1),复制构造函数(12.8),移动构造函数(12.8),复制赋值运算符(12.8),移动 赋值运算符(12.8)或析构函数(12.4),联合的相应成员函数必须是 用户提供或将为联盟隐式删除(8.4.3)。
没有提及不会是一个成员拥有默认成员初始化程序的情况。
对于C ++ 14,同样的注释仍然在草案n4296中,所以我认为在实际的C ++标准中它应该仍然是相同的。注释当然是非规范性的,但它们的目的是更清楚地对标准进行解释,因此我认为对cppreference的解释是错误的,因为它不尊重该注释,并且gcc解释是正确的。