联合公共初始序列与原始

Nir*_*man 17 c++ unions language-lawyer c++11 c++14

我试图更好地理解关于联合和共同的初始序列规则的相当令人惊讶的发现.常见的初始序列规则是(class.mem 23):

 在具有struct类型T1的活动成员的标准布局并集中,允许读取结构类型T2的另一个union成员的非静态数据成员m,前提是m是T1和T2的公共初始序列的一部分; 行为就像提名T1的相应成员一样.

所以,给定:

struct A {
  int a;
  double x;
};

struct B {
  int b;
};

union U {
  A a;
  B b;
};

U u;
u.a = A{};
int i = u.b.b;
Run Code Online (Sandbox Code Playgroud)

这是定义的行为,i应该具有值0(因为A并且B具有第一个成员的CIS,a int).到现在为止还挺好.令人困惑的是,如果B被简单的int替换:

union U {
  A a;
  int b;
};

...
int i = u.b;
Run Code Online (Sandbox Code Playgroud)

根据常见初始序列的定义:

两种标准布局结构类型的通用初始序列是......

所以CIS只能在两个标准布局结构之间应用.反过来:

标准布局结构是使用类键结构或类键类定义的标准布局类.

所以原始类型肯定不符合条件; 也就是说它没有任何CIS,所以A没有CIS int.因此标准说第一个例子是定义的行为,但第二个例子是UB.这对我来说根本没有任何意义; 直觉上,编译器至少受原始类型和类的限制.如果这是故意的,是否有任何押韵或理由(可能是对齐相关的)为什么这是有意义的?这可能是一个缺陷吗?

Dav*_*ing 1

ninjalj说得对:该规则的目的是支持标记联合(标记在前面)。虽然此类联合中支持的类型之一可能是无状态的(除了标签之外),但可以通过创建仅包含标签的结构来轻松解决这种情况。因此,不需要将规则扩展到结构之外,并且默认情况下,出于优化和未来标准化灵活性的常见原因,应将未定义行为的异常(类似于本例中的严格别名)保持在最低限度。