将通用初始序列与原语合并 [英] Union common initial sequence with primitive

查看:72
本文介绍了将通用初始序列与原语合并的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图更好地理解有关联合和通用初始序列规则的一个相当令人惊讶的发现。常见的初始序列规则说(class.mem 23):


在结构布局为T1的活动成员的标准布局联合中,允许读取结构类型为T2的另一个并集成员的非静态数据成员m,条件是m是T1和T2的公共初始序列的一部分;


因此,给定:

 结构A {
int a;
double x;
};

结构B {
int b;
};

工会U {
A a;
B b;
};

U u;
u.a = A {};
int i = u.b.b;

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

 联盟U {
A a;
int b;
};

...
int i = u; b;

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


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


所以CIS只能在两个标准布局结构之间应用。然后依次是:


标准布局结构是使用class-key结构或class-key类定义的标准布局类。


因此,原始类型绝对不符合条件;那是因为它不能具有任何内容的CIS,因此 A 没有具有 int 的CIS。因此,标准说第一个示例是定义的行为,而第二个示例是UB。这对我根本没有任何意义。直观上来说,编译器至少受原始类型和类的限制。如果这是故意的,那么为什么这有道理或理由(也许与对齐有关)?

解决方案

ninjalj 是否正确:此规则的目的是支持带标签的联合(在标签的前面)。尽管此类联合中支持的一种类型可能是无状态的(除了标签之外),但通过制作仅包含标签的结构,可以轻松解决这种情况。因此,无需将规则扩展到结构之外,并且默认情况下,出于优化和未来标准化灵活性的通常原因,此类未定义行为的例外情况(在这种情况下类似于严格的别名)应保持在最低水平。 p>

I am trying to better understand a rather surprising discovery regarding unions and the common initial sequence rule. The common initial sequence rule says (class.mem 23):

 In a standard-layout union with an active member of struct type T1, it is permitted to read a non-static data member m of another union member of struct type T2 provided m is part of the common initial sequence of T1 and T2; the behavior is as if the corresponding member of T1 were nominated.

So, given:

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;

This is defined behavior and i should have the value 0 (because A and B have a CIS of their first member, an int). So far, so good. The confusing thing is that if B is replaced by simply an int:

union U {
  A a;
  int b;
};

...
int i = u.b;

According to the definition of common initial sequence:

The common initial sequence of two standard-layout struct types is...

So CISs can only apply between two standard-layout structs. And in turn:

A standard-layout struct is a standard-layout class defined with the class-key struct or the class-key class.

So a primitive type very definitely does not qualify; that is it cannot have a CIS with anything, so A has no CIS with an int. Therefore the standard says that the first example is defined behavior, but the second is UB. This simply does not make any sense to me at all; the compiler intuitively is at least as restricted with a primitive type as with a class. If this is intentional, is there any rhyme or reason (perhaps alignment related) as to why this makes sense? Is it possibly a defect?

解决方案

ninjalj has it right: the purpose of this rule is to support tagged unions (with tags at the front). While one of the types supported in such a union could be stateless (aside from the tag), this case can be trivially addressed by making a struct containing just the tag. Thus, there is no need for extending the rule beyond structs, and by default such exceptions to undefined behavior (akin to strict aliasing in this case) should be kept to a minimum for the usual reasons of optimization and flexibility of future standardization.

这篇关于将通用初始序列与原语合并的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆