说编译器可以将下面的表达式"a->i"替换为其值 1 是否正确,因为...?
Is it correct to say that the compiler can replace the expression `a->i` below by its value 1 because...?
下面的代码在GCC,clang和VS2017中编译,return
语句中的表达式a->i
替换为其常量值1。说这是有效的是否正确,因为表达式a->i
中没有使用 odra
?
struct A
{
static const int i = 1;
};
int f()
{
A *a = nullptr;
return a->i;
}
PS:我相信a
在表达式中没有使用a->i
,因为它满足 [basic.def.odr]/4 中的"除非"条件,如下所示:
名称显示为潜在计算值的变量
x
表达式ex
由ex
使用 ODR,除非应用 左值到重值的转换 (7.1( 到x
产生常量表达式 (8.6( 不援引任何非平凡的内容 函数,如果x
是一个对象,则ex
是表达式e
的潜在结果集合的一个元素,其中 左值到重值转换 (7.1( 应用于e
,或者e
丢弃值表达式 (8.2(。
特别是,表达式ex == a
是表达式e == a->i
的潜在结果集合的一个元素,根据 [basic.def.odr]/2 (2.3(,包含表达式ex
,其中左值到右值的转换应用于e
。
a
被 ODR 使用,因为你失败了"除非"的第一部分:
将左值到右值转换 (7.1( 应用于
x
会产生一个常量表达式 (8.6(,该表达式不调用任何非平凡函数
将左值到右值的转换应用于a
不会生成常量表达式。
其余的是核心问题315和232。
您的分析以另外两种方式中断:
- "对象表达式"是使用类成员访问的
.
形式定义的,因此在应用 [basic.def.odr]/2.3 之前,您需要将a->i
重写为点形式,即(*a).i
。a
不是该表达式的潜在结果集的成员。 - 该项目符号本身是有缺陷的,因为它是在考虑非静态数据成员的情况下编写的。对于静态数据成员,潜在结果集实际上应该是命名的静态数据成员 - 请参阅核心问题 2353,因此
a
加倍不是该表达式的潜在结果集的成员。
[expr.const]/2.7:
表达式
e
是核心常量表达式,除非e
的评估,遵循抽象机器的规则,将 计算以下表达式之一:
- [...]
- 左值到右值的转换,除非它应用于
- 整数或枚举类型的非易失性 gl值,引用具有前面的完整非易失性 const 对象 初始化,使用常量表达式初始化,或
- 引用字符串文本的子对象的非易失性 glvalue ,或
一种非易失性- gl值,它引用用
constexpr
定义的非易失性对象,或者引用 这样的对象,或- 文字类型的非易失性 gl值,指的是其生命周期始于
e
评估的非易失性对象;- [...]
i
是该类的static
成员...由于您可以通过使用实例的常规方法来访问类的static
成员,因此它们不特定于任何实例,因此您无需取消引用nullptr
指针(就像使用sizeof
运算符一样(。 您也可以使用简单的
return A::i;
语句,因为您无需创建实例即可访问它。 事实上,const
,编译器允许将其作为常量值进行管理,因此只有在您需要使用它的地址(通过&
运算符(的情况下,编译器才能绕过将其分配给只读内存。
以下示例将对此进行探测:
#include <iostream>
struct A {
static const int i = 1;
};
int main()
{
std::cout << ((A*)0)->i << std::endl;
std::cout << A::i << std::endl;
}
将打印
$ a.out
1
1
$ _
- 在cstlib中将#include_next替换为#include是否安全
- 使用 Rcpp 加速替换迭代算法中的列表和向量元素是否合法?
- 我是否应该在包含虚拟方法的类上使用'memcpy'?如果没有,如何替换它?
- 类似函数的宏参数名称替换是否保证永远不会发生?
- 字符串::是否替换了迭代器和引用?
- 说编译器可以将下面的表达式"a->i"替换为其值 1 是否正确,因为...?
- 编译器是否将常量变量替换为它们在 C++ 中的值
- 是否可以替换父类?
- JNI-是否可以用其他类替换类的实例化
- 如何查找查看一个字符串是否位于另一个字符串内部并替换它
- 如果在执行过程中替换二进制文件,"const"数组是否驻留在内存中?
- CRTP 静态多态性:是否可以用模拟替换基类
- 是否可以保证C++标准库容器调用可替换的新功能
- lambda 是否应该替换 C++ 中的函数模板
- 是否有 C++/C 的高效构建功能可以快速均匀地对 b 条目进行采样,而无需替换 n 个条目?
- 是否可以用#Define替换整行
- 是否有一种替换C风格的Bool数组的标准方法
- 是否有一种方法可以将变量列表传递给#Define指令,并导致其通过文字值替换字符串值
- 是否可以重载 wcout <<运算符以将其替换为 WriteConsoleW?
- 是否有任何情况将push_back替换为emplace_back不正确