c++ - 说编译器可以将下面的表达式 `a->i` 替换为其值 1 是否正确,因为...?
问题描述
下面的代码在 GCC、clang 和 VS2017 中编译,语句a->i
中的表达式return
被其常量值 1 替换。说这是有效的是否正确,因为表达式a
中没有使用 odr a->i
?
struct A
{
static const int i = 1;
};
int f()
{
A *a = nullptr;
return a->i;
}
PS:我相信表达式a
中没有使用 odr,a->i
因为它满足[basic.def.odr]/4中的“除非”条件,如下所示:
除非应用左值到右值转换 (7.1) 以
x
生成不调用任何非平凡函数的常量表达式 (8.6) 并且如果是对象,是表达式 的潜在结果集合中的一个元素,其中左值到右值转换 (7.1) 应用于,或者是丢弃值表达式 (8.2)。ex
ex
x
x
ex
e
e
e
特别是,根据[basic.def.odr]/2 (2.3)ex == a
,表达式是表达式 的潜在结果集合中的一个元素,其中包含表达式,其中左值到右值的转换应用于。 e == a->i
ex
e
解决方案
a
使用 odr 是因为您未通过“除非”的第一部分:
应用左值到右值的转换(7.1)来
x
产生一个不调用任何非平凡函数的常量表达式(8.6)
应用左值到右值的转换a
不会产生常量表达式。
您的分析以另外两种方式被破坏:
- “对象表达式”是使用
.
类成员访问的形式定义的,所以在应用[basic.def.odr]/2.3之前需要重写a->i
为点形式,即, 。不是该表达式的潜在结果集的成员。(*a).i
a
- 该项目符号本身是有缺陷的,因为它是在考虑非静态数据成员的情况下编写的。对于静态数据成员,潜在结果集实际上应该是命名的静态数据成员 - 请参阅核心问题 2353,因此
a
双重不是该表达式的潜在结果集的成员。
[expr.const]/2.7:
一个表达式
e
是一个核心常量表达式,除非根据e
抽象机的规则,对 的求值将求值以下表达式之一:
- [...]
- 左值到右值的转换,除非它应用于
- 一个整数或枚举类型的非易失性左值,它引用一个完整的非易失性 const 对象,该对象具有前面的初始化,用常量表达式初始化,或
- 引用字符串文字的子对象的非易失性泛左值,或
- 一个非易失性泛左值,它指的是一个用 定义的非易失性对象
constexpr
,或者指代这种对象的一个非可变子对象,或者- 文字类型的非易失性左值,指的是一个非易失性对象,其生命周期开始于 的评估
e
;- [...]
推荐阅读
- python - Python 3.8 解析导入路径
- api - Microsoft Graph API odata $filter 查询似乎不起作用
- azure-devops - 在 TFS 到 DevOps 迁移期间修复损坏的 TFS 工作项链接
- javascript - 获取已挂载的 vueJs 中图像的大小
- python - Python Google Spreadsheet API 气泡图未正确显示
- typescript - 在 svelte 文件中导出 typescript 类型
- html - 当我在 Django 中使用“扩展”和“阻止”时,我的 CSS 没有出现
- mongodb - 在 Upsert 操作中来自 MongoDB 的重复键错误
- python - 来自 Python 的 Rofi 通行证列表
- git - 如何使 zsh 完成显示所有参数?