Seb*_*Nag 3 c++ language-lawyer c++17
给出代码片段:
struct S {
static const int var = 0;
};
int function(const int& rVar){
return rVar;
}
int main()
{
return function(S::var);
}
Run Code Online (Sandbox Code Playgroud)
编译gcc 5.4.0:
g++ -std=c++17 main.cpp -o test
Run Code Online (Sandbox Code Playgroud)
导致以下链接错误:
/tmp/ccSeEuha.o: In function `main':
main.cpp:(.text+0x15): undefined reference to `S::var'
collect2: error: ld returned 1 exit status
§3.3来自ISO标准C++ 17草案n4296规定:
变量x的名称显示为潜在评估的表达式ex,除非将lvalue-to-rvalue转换(4.1)应用于x,产生不调用任何非平凡函数的常量表达式(5.20),否则由ex使用odr. ,如果x是一个对象,ex是表达式e的潜在结果集的一个元素,其中左值到右值的转换(4.1)应用于e [ 粗体格式添加],或者e是丢弃值表达式(第5条).
问:为什么var这里需要变量的定义?不var表示出现在outter函数调用表达式的潜在评估表达式S::var中的整数对象,它实际上通过引用获取参数,但最终应用了左值到右值的转换,因此不是如段落所述使用的odr?
但是最后应用了左值到左值的转换,因此如段落中所述的那样没有使用?
我认为,另一个表达式中的左值到右值的转换是无关紧要的.在表达式S::var中没有应用于子表达式的左值到右值转换function(S::var),因此该异常不适用.
从常识的角度考虑,而不是分析规则:function可以在另一个转换单元中定义,因此编译器不一定知道如何使用引用.它不能只是将值的副本发送给函数,并希望函数定义不会以需要定义被引用对象的方式使用该对象.同样,在编译函数时,编译器不能假定所有函数调用都会发送除对现有对象的引用之外的任何内容.
从技术上讲,我认为内联函数的引用参数可能有更复杂的异常,但标准中没有这样的例外.并且应该没有,因为在那些情况下它会强制进行内联扩展.在实践中,如果发生内联函数的扩展,编译器的行为可能与此异常完全相同,因为odr违规具有未定义的行为.