有了这个代码:
struct A
{
int i;
const int b;
};
// The union is to verify that A is a type that can be used in a union.
union U
{
A a;
int b;
};
int main()
{
U a = {1, 1};
U b = {2, 1};
}
g++ 版本 4.8.3 抱怨一个错误:
a.cpp:9:4: error: member ‘A U::a’ with copy assignment operator not allowed in union
A a;
^
a.cpp:9:4: note: unrestricted unions only available with -std=c++11 or -std=gnu++11
但 clang 3.5.0 编译此代码没有错误。哪一个是正确的?这是编译器错误吗?
我尝试解决这个问题:
来自C++03标准第9.5节第1段:
在联合体中,任一时刻最多有一个数据成员处于活动状态,即任一时刻联合体中最多可以存储一个数据成员的值。 [注意:为了简化联合的使用,做了一个特殊的保证:如果一个 POD 联合包含多个共享公共初始序列 (9.2) 的 POD 结构,并且如果该 POD 联合类型的对象包含以下之一POD 结构体,允许检查任何 POD 结构体成员的公共初始序列;见 9.2。 ] 联合的大小足以包含其最大的数据成员。每个数据成员的分配就好像它是结构体的唯一成员一样。联合可以有成员函数(包括构造函数和析构函数),但不能有虚函数(10.3)。联合不得有基类。联合不得用作基类。具有非平凡构造函数(12.1)、非平凡复制构造函数(12.8)、非平凡析构函数(12.4)或非平凡复制赋值运算符(13.5.3、12.8)的类的对象不能是联合的成员,此类对象的数组也不能。如果联合包含静态数据成员或引用类型的成员,则程序格式错误。
来自C++03标准第12.8节第10和11段:
如果类定义没有显式声明复制赋值运算符,则隐式声明一个。类 X 的隐式声明的复制赋值运算符将具有以下形式X& X::operator=(const X&)
如果 X 的每个直接基类 B 都有一个复制赋值运算符,其参数类型为 const B&、const volatile B& 或 B,并且对于 X 的类类型 M(或其数组)的所有非静态数据成员,每个此类类型有一个复制赋值运算符,其参数类型为 const M&、const volatile M& 或 M。
Otherwise, the implicitly declared copy assignment operator will have the form X& X::operator=(X&)
...
如果类 X 是隐式声明的,并且类 X 没有虚函数 (10.3) 和虚基类 (10.1),并且 X 的每个直接基类都有一个简单的复制赋值运算符,则类 X 的复制赋值运算符是简单的,并且对于X 的所有非静态数据成员都是类类型(或其数组),每个这样的类类型都有一个简单的复制赋值运算符;否则复制赋值运算符是不平凡的。
我不确定哪个编译器是正确的,因为我不知道常量成员是否有一个简单的复制赋值运算符。
Edit:编译命令为:
clang++ a.cpp -o a
g++ a.cpp -o a
Edit2:为了表明 g++ 没有抱怨 A::bconst
但 A 没有构造函数,我也尝试了这个程序:
struct A
{
int i;
const int b;
};
int main()
{
A a = {1, 1};
}
在 g++ 和 clang++ 上编译都没有错误:
g++ b.cpp -o b
clang++ b.cpp -o b