【发布时间】:2020-04-23 11:54:30
【问题描述】:
C++ 标准的N4778 草案(2018 年)包含以下部分:
7.2.1 [basic.lval]
如果程序尝试通过以下类型之一以外的左值访问对象的存储值,则行为未定义:
- 对象的动态类型,
- 对象动态类型的 cv 限定版本,
- 与对象的动态类型类似(如 7.5 中定义)的类型,
- 对象的动态类型对应的有符号或无符号类型,
- 一种有符号或无符号类型,对应于对象动态类型的 cv 限定版本,
- 一种聚合或联合类型,在其元素或非静态数据成员(递归地包括子聚合或包含联合的元素或非静态数据成员)中包含上述类型之一,
- 一种类型,它是对象动态类型的(可能是 cv 限定的)基类类型,
char、unsigned char或std::byte类型。
但是,draft at eel.is/c++draft/lists 只有 3 个子弹(我突出显示了常见的):
如果程序尝试通过类型与以下类型之一不相似 ([conv.qual]) 的泛左值访问对象的存储值,则行为未定义:
- 对象的动态类型,
- 对象的动态类型对应的有符号或无符号类型,
char、unsigned char或std::byte类型。
P1359R0 解释更改:
[basic.lval] 的别名规则改编自 C,并添加了 C++。然而,一些点要么不适用,要么被其他点所包含。例如,在 C 中需要为结构赋值提供聚合和联合类型,在 C++ 中,这是通过 C++ 中的构造函数和赋值运算符完成的,而不是通过访问完整的对象。 ... 有人建议应扩展别名规则,以允许具有固定基础类型的枚举对象为具有该基础类型的对象设置别名。
您能否通俗地解释一下这种措辞更改的实际后果?据我了解,建议enum class E : T { ... }; 允许别名T。它是否正确?除此以外的其他内容是否会被定义/未定义?
【问题讨论】:
-
不确定您从哪里获得
enum更改。根据我对引用段落的阅读,这只是人们建议的内容。我对它第一部分的阅读是不应该有任何实际的改变,因为这是对冗余/无意义规则的编辑/清理操作。也许其他人可以更详细地介绍。 -
@curiousguy 你知道“对象的动态类型”这个词是有缺陷的,不是吗?
-
@supercat 不确定我明白你的意思。我认为放弃对象的“动态类型”没有问题。 “动态类型”是表达式的属性。将“动态类型”广泛用作对象的属性是有缺陷的。
-
@LanguageLawyer:据我所知,C 和 C++ 标准中的规则令人困惑,因为对于它们的含义从未达成共识。当它们第一次被编写时,委员会期望编译器会尝试在不这样做会很愚蠢的情况下有用地处理程序,即使是标准也会允许这种愚蠢的行为;因此,委员会成员愿意同意那些没有规定程序员需要做的所有事情的规则,因为他们希望编译器无论如何都会支持必要的行为。
-
@LanguageLawyer:从那时起,就需要制定更精确的规则,但任何明确的规则都会不同意某人对规则应该意味着什么的想法,因此唯一可以达成共识是那些非常模糊以至于他们可以“同意”关于他们应该意味着什么的相互矛盾的想法。
标签: c++ language-lawyer strict-aliasing