是什么这个 C++ FAQ试图传达?
如果(并且仅当)它具有类外定义,您可以获取静态成员的地址:
class AE {
// ...
public:
static const int c6 = 7;
static const int c7 = 31;
};
const int AE::c7; // definition
int f()
{
const int* p1 = &AE::c6; // error: c6 not an lvalue
const int* p2 = &AE::c7; // ok
// ...
}
Run Code Online (Sandbox Code Playgroud)
然而这编译!
常见问题解答中的评论非常误导; 这两个AE::c6和
AE::c7是左值.如果没有定义AE::c7,则相关代码违反了一个定义规则:
除非它是未评估的操作数或其子表达式,否则可能会评估表达式.名称显示为潜在评估表达式的变量是odr-used,除非它是满足出现在常量表达式中的要求的对象,并且立即应用左值到右值转换.[...]
[...]
每个程序应该只包含该程序中使用的每个非内联函数或变量的一个定义; 无需诊断.
实际上,如果
编译器实际需要对象的地址,链接器通常会生成错误.在您的情况下,如果p2以后不使用,那么编译器将不需要该地址,因为优化将删除定义p1.发生这种情况的更常见的情况如下:
std::vector<int> v;
v.push_back( AE::c6 );
Run Code Online (Sandbox Code Playgroud)
由于std::vector<>::push_back需要引用,因此没有立即的左值到右值转换,并且需要定义.在实践中,std::vector<>::push_back是一个模板函数(通常是内联的),因此编译器可以看到它的实现,并将值传播到函数中,实际发生左值到右值转换的位置,代码将编译和工作.但它仍然是正式未定义的行为.