为什么s :: x不使用ODR

Why is S::x not odr-used?

本文关键字:ODR 为什么      更新时间:2023-10-16

从cppreference中考虑此示例:

struct S { static const int x = 1; };
void f() { &S::x; } // discarded-value expression does not odr-use S::x

我同意 &S::x dasved-value表达式,因为标准说(9.2,段落1 [stmt.expr] N4700)

表达式语句具有形式

expression-statement:
    expression_opt ;

表达式是一个丢弃的值表达式(第8条)...

但是,对于S::x而言,这足以不被 odr使用?6.2,第3段[basic.def.odr]状态

x的变量CC_3,其名称以潜在评估的表达式ex odr used ,除非

  • ...
  • 如果x是一个对象, ex是表达式e 的潜在结果集的元素
    • 将LVALUE到RVALUE转换(7.1)应用于e
    • e是一个丢弃的值表达式(第8条)

问题是丢弃的值表达式&S::x没有潜在的结果(这意味着S::x不是&S::x的潜在结果),正如您可以从6.2,第2段[Basic.Def.odr]段中看到的那样:blockquote>

...表达式e的潜在结果集定义如下:

  • 如果e是ID-表达(8.1.4),则该集合仅包含e
  • 如果e是带有数组操作数的订阅操作(8.2.1),则该集合包含该操作数的潜在结果。
  • ...
  • 否则,该集合为空。

那么,您如何解释S::x没有使用ODR?

它确实被用了。您的分析是正确的(我在不久前修复了该示例)。

是的,在示例中, &S::x odr-uses S::x

[basic.def.odr]/4

一个可变的x,其名称显示为潜在评估的表达式ex odr-odr-使用,除非将lvalue-to-rvalue转换 x应用于 CC_25>不调用任何非平凡的功能,如果x是对象,则EX是表达式E的潜在结果集的元素,其中lvalue-to-rvalue转换应用于E,或者E是丢弃的价值表达式。

对象的地址绝不是恒定的表达式。这就是为什么S::x&S::x中使用ODR。

证明最后断言是合理的:

[expr.const]/6

常数表达式是glvalue核心常数表达式,它是指一个实体,该实体是恒定表达式的允许结果(如下所示),或者是一个值得满足以下约束[...]的prvalue core常数表达式表达式表达式。

[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

该链接将使DOU失败至:"未定义的S::x"。

因此,我的结论是:在不使用的情况下进行地址,根本不计数