this 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
// ...
}
然而这compiles !
答案 0 :(得分:9)
您使用-O2
进行编译。编译器可以优化const int* p1 = &AE::c6;
赋值(因为它没有效果),因此它不需要最终代码中AE::c6
的地址,这就是它编译的原因。
它在没有优化的情况下给出了链接器错误。
如果您开始使用p1
(例如std::cout << p1 << p2 << std::endl;
)Link
答案 1 :(得分:5)
常见问题解答中的评论非常具有误导性; AE::c6
和{。}
AE::c7
是左值。如果没有AE::c7
的定义,
有问题的代码违反了一个定义规则:
表达式可能会被评估,除非它是 未评估的操作数或其子表达式。一个变量 其名称显示为可能评估的表达式 除非它是满足要求的对象,否则使用odr 出现在常量表达式和左值到右值 转换立即应用。 [...]
[...]
每个程序应包含每个程序的一个定义 非内联函数或在其中使用的变量 程序;无需诊断。
实际上,链接器通常会生成错误 if
编译器实际上需要对象的地址。在你的
如果p2
以后没有使用过,那么编译器就不需要了
地址,因为优化将删除p1
的定义。
发生这种情况的更常见的情况是像
以下内容:
std::vector<int> v;
v.push_back( AE::c6 );
由于std::vector<>::push_back
需要参考,因此没有
立即左值到右值转换,定义是
需要。实际上,std::vector<>::push_back
是一个模板
函数(通常是内联的),所以编译器可以看到它
实现,并将值传播到函数中
到实际的左值到右值转换的地方
发生,代码将编译和工作。但它仍然存在
正式未定义的行为。