我知道静态const成员必须具有out-ouf-class定义,因为它们使用起来很多。但问题是,即使没有成员定义,我的程序也会编译并运行得很好。
让我们从C ++ FAQ中看一下这个例子:
class AE
{
public:
static const int c6 = 7;
static const int c7 = 31;
};
const int AE::c7; // definition
void f()
{
const int* p1 = &AE::c6; // error: c6 not an lvalue
const int* p2 = &AE::c7; // ok
cout << *p1 << endl;
}
int main()
{
f();
const int* p1 = &AE::c6;
std::cout << p1 << "\n";
return 0;
}
//RESULT:
// 7
// 00007FF735E7ACE8
我没有看到任何错误。我使用Visual Studio 2015,这段代码编译并运行得很好。
我的问题:这是针对msvc的,还是有一些我不知道的语言变化?
更新:这不是重复,正如我在一开始所说:我确实理解这假设是如何工作的,我不明白为什么它不能正常工作。
答案 0 :(得分:4)
该程序明确违反了您在问题中所述的一个定义规则。但是在这种情况下,该标准不需要诊断。这在3.2定义规则[basic.def.odr]§4(强调我的)
中是明确的每个程序都应该包含每个非内联函数或变量使用的变量的一个定义 在该计划中; 无需诊断。
和1.4实施合规性[intro.compliance]§2.3说:
如果程序包含违反不需要诊断的规则,则为本国际 标准对该程序的实施没有要求。
这意味着gcc对该程序的阻塞是正确的,因为违反了一条规则。但是当MSVC接受它作为编译器扩展(*)而没有警告时,这不是一个错误,因为标准在这里没有要求。
我们处于编译时未定义的行为,名为格式错误的程序,无需诊断。编译器实现可以自由地执行它想要的任务:
(*)更确切地说,如果记录,它是编译器扩展。不幸的是,我目前没有MSVC编译器完整的文档,所以我不能说它是否是文档化的,是一个符合标准的扩展,或者不是,只是嗯...一个可能的程序执行
这是OP代码的一个细微变化,证明编译器确实提供了一个定义:
#include <iostream>
class AE {
// ...
public:
static const int c6 = 7;
static const int c7 = 31;
};
const int AE::c7; // definition
int main()
{
const int* p1 = &AE::c6; // error: c6 not an lvalue
const int* p2 = &AE::c7; // ok
// ...
std::cout << *p1 << "(" << p1 << ") - " << *p2 << "(" << p2 << ")" << std::endl;
return 0;
}
输出是(使用旧的MSVC 2008,调试模式以避免尽可能多的优化):
7(00DF7800) - 31(00DF7804)
是预期值和连续地址
使用相同的代码,Clang 3.4在链接时抱怨(如预期的那样)
undefined reference to `AE::c6'
答案 1 :(得分:1)
恰好发生,你的编译器已经应用了一些优化,这意味着在这种情况下它并不要求你遵循一个定义规则。
但是,C ++标准仍然要求您这样做,因此您的程序具有未定义的行为。该标准不要求编译器在您违反此特定规则时告诉您,因此选择不这样做。实际上,它必须付出额外的努力才能发现问题。
答案 2 :(得分:0)
C ++标准说([basic.def.odr] 3.2第2段)“变量 其名称显示为潜在评估的表达式是使用odr 除非它是满足出现要求的对象 在常量表达式(5.19)和左值到右值的转换中 (4.1)立即申请。“