[英]Why is S::x not odr-used?
从cppreference考虑以下示例:
struct S { static const int x = 1; };
void f() { &S::x; } // discarded-value expression does not odr-use S::x
我同意&S::x
是丢弃值表达式 ,由于标准说(9.2,第1段[stmt.expr]从N4700 )
表达式语句具有以下形式
expression-statement: expression_opt ;
该表达式是一个废弃值表达式(第8条)...
但是,足以让S::x
不被使用吗? 6.2第3段[basic.def.odr]指出
变量
x
,其名称显示为潜在评估表达ex
是ODR-使用ex
,除非
- ...
- 如果
x
是对象,则ex
是表达式e
的一组潜在结果的元素 ,其中
- 左值到右值转换(7.1)应用于
e
,或者e
是一个舍弃值表达式(第8条) 。
问题是,废弃值表达式&S::x
没有潜在结果(这意味着S::x
不是&S::x
的潜在结果),如您从6.2第2段中所见[basic.def .odr]:
...表达式
e
的潜在结果集定义如下:
- 如果
e
是id表达式(8.1.4),则该集合仅包含e
。- 如果
e
是具有数组操作数的下标操作(8.2.1),则该集合包含该操作数的潜在结果。- ...
- 否则,集合为空。
然后,您如何解释S::x
未被使用?
它确实是很少使用的。 你的分析是正确的(我固定的例如前一阵子 )。
是的,在示例中, &S::x
odr使用S::x
。
[basic.def.odr]/4
变量
x
,其名称显示为潜在评估表达ex
是ODR-使用ex
,除非施加左值到右值转换到x
产生一个常量表达式不调用任何非平凡的功能,并且如果x是一个对象,ex是表达式e的一组潜在结果的元素,其中将左值到右值转换应用于e或e是舍弃值表达式。
对象的地址绝不是常量表达式。 这就是为什么S::x
就是ODR-应用于&S::x
。
为了证明最后一个断言的合理性:
[expr.const]/6
常量表达式可以是glvalue核心常量表达式,指的是作为常量表达式允许的结果的实体(如下定义),或者是prvalue核心常量表达式,其值满足以下约束[...]
和
[expr.const]/2.7
2)表达式
e
是核心常量表达式,除非按照抽象机的规则对e
求值将对以下表达式之一求值:
[...]
2.7)左值到右值的转换,除非将其应用于
(以下几点均不适用:)
2.7.1)整数或枚举类型的非易失性glvalue,它引用具有先前初始化,用常量表达式初始化的完整非易失性const对象,或
2.7.2)非易失性glvalue,它引用字符串文字的子对象,或者
2.7.3)非易失性glvalue,它引用用constexpr定义的非易失性对象,或引用该对象的非可变子对象,或
2.7.4)文字类型的非易失性glvalue,指的是其寿命在e
的求值内开始的非易失性对象;
声明const int
,除非您使用其地址,否则编译器可能会将其完全丢弃。 拿地址是不够的。
丢弃并不意味着它不会被评估,而是意味着没有包含const值的内存地址,编译器只是将const变量替换为其值,因为它只是一个宏。
另外,当使用指向它的指针并从该指针取回值时,不会给编译器留下太多的印象,它只会忽略它并使用该值。
以下代码显示了该代码,尽管未声明S::x
却可以对其进行编译和运行(我已通过多个编译器对其进行了测试,但我仍不确定是否所有代码都已成功编译...):
#include <iostream>
using namespace std;
struct S
{
static const int x=0;
};
//const int S::x; //discarded
int main()
{
const int *px = &S::x; //taking the address
cout<< *px <<endl; //print the value - OK
return 0;
}
但是,如果我尝试使用地址本身(而不是值),例如:
cout<< px <<endl; //print the address - Will be failed
链接将失败,原因是:“对S::x
未定义引用”。
因此,我的结论是: 不使用地址就不算什么 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.