C++ 为什么不使用odr?
从以下方面考虑此示例: 我同意C++ 为什么不使用odr?,c++,language-lawyer,c++17,C++,Language Lawyer,C++17,从以下方面考虑此示例: 我同意&S::x是一个废弃的值表达式,因为标准中说(9.2,第1段[stmt.expr]) 表达式语句具有以下形式: expression-statement: expression_opt ; 表达式是一个废弃的值表达式(第8条) 然而,对于不使用odr的S::x来说,这足够了吗?6.2第3段[基本定义odr]规定 变量x的名称显示为可能计算的表达式ex是ex使用的odr,除非 如果x是一个对象,ex是表达式e的潜在结果集的一个元素,其中 左值到右值的转
&S::x
是一个废弃的值表达式,因为标准中说(9.2,第1段[stmt.expr])
表达式语句具有以下形式:
expression-statement:
expression_opt ;
表达式是一个废弃的值表达式(第8条)
然而,对于不使用odr的S::x
来说,这足够了吗?6.2第3段[基本定义odr]规定
变量x
的名称显示为可能计算的表达式ex
是ex
使用的odr,除非
- 如果
是一个对象,x
是表达式ex
的潜在结果集的一个元素,其中e
- 左值到右值的转换(7.1)应用于
,或e
是一个废弃的值表达式(第8条)e
- 左值到右值的转换(7.1)应用于
&S::x
没有潜在结果(这意味着S::x
不是&S::x
的潜在结果),如6.2第2段[basic.def.odr]所示:
。。。表达式e
的潜在结果集定义如下:
- 如果
是一个id表达式(8.1.4),则集合仅包含e
e
- 如果
是带有数组操作数的下标运算(8.2.1),则集合包含该操作数的潜在结果e
- 否则,集合为空。
那么,您如何解释
S::x
未使用odr?是的,在示例中,&S::x
odr使用S::x
变量x
的名称显示为可能计算的表达式ex
是ex
使用的odr,除非将左值到右值的转换应用于x
会产生一个常量表达式,该表达式不调用任何非平凡函数,并且如果x是一个对象,ex是表达式e的潜在结果集的一个元素,其中左值到右值的转换应用于e,或者e是丢弃的值表达式
对象的地址从来不是一个常量表达式。这就是为什么在&s::x
中使用odr的原因
为了证明最后的断言是正确的:
常量表达式是指作为常量表达式(定义如下)的允许结果的实体的glvalue核心常量表达式,或者是其值满足以下约束条件的prvalue核心常量表达式[…]
及
2) 表达式e
是一个核心常量表达式,除非遵循抽象机器规则对e
的求值将求值以下表达式之一:[…]
2.7)左值到右值的转换,除非适用于 (以下各点均不适用:) 2.7.1)整型或枚举型的非易失性glvalue,指的是一个完整的非易失性常量对象,具有前面的初始化、用常量表达式初始化或
2.7.2) 引用字符串文字的子对象的非易失性glvalue,或
2.7.3) 一种非易失性glvalue,它引用用constexpr定义的非易失性对象,或引用此类对象的不可变子对象,或
2.7.4) 一种文本类型的非易失性glvalue值,指的是一个非易失性对象,其生存期开始于
e
的计算范围内
声明
const int
时,编译器可能会完全丢弃它,除非使用它的地址获取地址不够
丢弃并不意味着不计算该值,而是意味着没有包含常量值的内存地址,编译器只是用它的值替换常量变量,因为它只是一个宏
此外,当获取指向它的指针并从指针中获取值时,不会给编译器留下太多印象,它只是忽略它并使用该值
下面的代码显示了这一点,尽管没有声明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;
}
#包括
使用名称空间std;
结构
{
静态常数int x=0;
};
//常量int S::x//丢弃的
int main()
{
const int*px=&S::x;//获取地址
cout确实使用了odr。您的分析是正确的(我修复了该示例)。标准措辞的另一个问题是,S::x
不是一个名称。它是一个限定id。但显然是“一个变量x,其名称…”也应该适用于x
作为一个合格的id。是的,这是我们这边的一个bug。修复了@M.M类似的东西?@T.C.让丢弃的值表达式&s::x
odr使用x
?@xskxzr获取某个东西的地址通常要求该东西存在。雕刻出来的好处是什么这种情况下的例外情况是:问题是被标记的,这意味着OP希望得到ISO C++标准的引用支持。它编译是不相关的(实际上很多ODR违规编译得很好)。。我不打算写一个答案只是为了确认我在评论中写的内容,但出于某种原因,这个问题吸引了很多错误的答案:|我很感激。谢谢!&S::x
不是左值(因此不能进行左值到右值的转换),而&
不会导致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