首页 > 解决方案 > 说编译器可以将下面的表达式 `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)。exex xxexeee

特别是,根据[basic.def.odr]/2 (2.3)ex == a ,表达式是表达式 的潜在结果集合中的一个元素,其中包含表达式,其中左值到右值的转换应用于。 e == a->iexe

标签: c++language-lawyerone-definition-rule

解决方案


a使用 odr 是因为您未通过“除非”的第一部分:

应用左值到右值的转换(7.1)来x产生一个不调用任何非平凡函数的常量表达式(8.6)

应用左值到右值的转换a不会产生常量表达式。

其余的是核心问题315232


您的分析以另外两种方式被破坏:

  • “对象表达式”是使用.类成员访问的形式定义的,所以在应用[basic.def.odr]/2.3之前需要重写a->i为点形式,即, 。不是该表达式的潜在结果集的成员。(*a).ia
  • 该项目符号本身是有缺陷的,因为它是在考虑非静态数据成员的情况下编写的。对于静态数据成员,潜在结果集实际上应该是命名的静态数据成员 - 请参阅核心问题 2353,因此a双重不是该表达式的潜在结果集的成员。

[expr.const]/2.7:

一个表达式e是一个核心常量表达式,除非根据e抽象机的规则,对 的求值将求值以下表达式之一:

  • [...]
  • 左值到右值的转换,除非它应用于
    • 一个整数或枚举类型的非易失性左值,它引用一个完整的非易失性 const 对象,该对象具有前面的初始化,用常量表达式初始化,或
    • 引用字符串文字的子对象的非易失性泛左值,或
    • 一个非易失性泛左值,它指的是一个用 定义的非易失性对象constexpr,或者指代这种对象的一个​​非可变子对象,或者
    • 文字类型的非易失性左值,指的是一个非易失性对象,其生命周期开始于 的评估e
  • [...]

推荐阅读