使用 `{}` 在 C++ 中聚合初始化联合
Aggregate initialization of a union in C++ with `{}`
在下面的程序中,联合 U
有两个字段 a
和 b
,每个字段都有不同的默认值。如果使用聚合初始化创建类型 U
的变量 {}
联合的值和活动成员是什么?
#include <iostream>
struct A { int x = 1; };
struct B { int x = 0; };
union U {
A a;
B b;
};
int main() {
U u{};
std::cout << u.a.x;
}
令人惊讶的是,编译器在这里出现分歧:Clang 打印 1
而 GCC 打印 0
,演示:https://gcc.godbolt.org/z/8Tj4Y1Pv1
其中一个编译器是否存在错误或此处的行为未由标准定义?
Clang 正确,GCC 错误
An aggregate is an array or a class ([class]) with
- (1.1) no user-declared or inherited constructors ([class.ctor]),
- (1.2) no private or protected direct non-static data members ([class.access]),
- (1.3) no virtual functions ([class.virtual]), and
- (1.4) no virtual, private, or protected base classes ([class.mi]).
A
、B
和 U
都是聚合 classes,虽然之前是 non-union聚合 classes,前者不符合条件。
根据[dcl.init.aggr]/5[强调我的]:
For a non-union aggregate, each element that is not an explicitly
initialized element is initialized as follows:
- (5.1) If the element has a default member initializer ([class.mem]), the element is initialized from that initializer.
- (5.2) Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).
- (5.3) Otherwise, the program is ill-formed.
If the aggregate is a union and the initializer list is empty, then
- (5.4) if any variant member has a default member initializer, that member is initialized from its default member initializer;
- (5.5) otherwise, the first member of the union (if any) is copy-initialized from an empty initializer list.
因此
U u{};
是聚合初始化,结果union的第一个数据成员class,即A
类型的数据成员a
(这是一个非联合聚合class), 是从一个空的初始化列表复制初始化的。由于类型 A
的单个数据成员 x
具有默认成员初始值设定项,因此根据上面的 [dcl.init.aggr]/5.1,数据成员 x
由其默认成员初始值设定项初始化。
因此,Clang是对的,GCC是错的。
GCC 错误报告
在下面的程序中,联合 U
有两个字段 a
和 b
,每个字段都有不同的默认值。如果使用聚合初始化创建类型 U
的变量 {}
联合的值和活动成员是什么?
#include <iostream>
struct A { int x = 1; };
struct B { int x = 0; };
union U {
A a;
B b;
};
int main() {
U u{};
std::cout << u.a.x;
}
令人惊讶的是,编译器在这里出现分歧:Clang 打印 1
而 GCC 打印 0
,演示:https://gcc.godbolt.org/z/8Tj4Y1Pv1
其中一个编译器是否存在错误或此处的行为未由标准定义?
Clang 正确,GCC 错误
An aggregate is an array or a class ([class]) with
- (1.1) no user-declared or inherited constructors ([class.ctor]),
- (1.2) no private or protected direct non-static data members ([class.access]),
- (1.3) no virtual functions ([class.virtual]), and
- (1.4) no virtual, private, or protected base classes ([class.mi]).
A
、B
和 U
都是聚合 classes,虽然之前是 non-union聚合 classes,前者不符合条件。
根据[dcl.init.aggr]/5[强调我的]:
For a non-union aggregate, each element that is not an explicitly initialized element is initialized as follows:
- (5.1) If the element has a default member initializer ([class.mem]), the element is initialized from that initializer.
- (5.2) Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).
- (5.3) Otherwise, the program is ill-formed.
If the aggregate is a union and the initializer list is empty, then
- (5.4) if any variant member has a default member initializer, that member is initialized from its default member initializer;
- (5.5) otherwise, the first member of the union (if any) is copy-initialized from an empty initializer list.
因此
U u{};
是聚合初始化,结果union的第一个数据成员class,即A
类型的数据成员a
(这是一个非联合聚合class), 是从一个空的初始化列表复制初始化的。由于类型 A
的单个数据成员 x
具有默认成员初始值设定项,因此根据上面的 [dcl.init.aggr]/5.1,数据成员 x
由其默认成员初始值设定项初始化。
因此,Clang是对的,GCC是错的。