这是一个问题,其原因对我来说相当模糊,但幸运的是,其解决方法很容易。
考虑以下代码(我将其称为main.cpp
):
#include <algorithm>
struct Foo {
static constexpr float BAR = .42;
float operator()() const noexcept {
float zero = .0;
return std::min(zero, BAR);
}
};
int main() {
Foo foo;
foo();
}
当我尝试编译它时,我收到错误:
foobar:〜/ stackoverflow $ g ++ -std = c ++ 11 main.cpp
/tmp/ccjULTPy.o:在函数&#39; Foo :: operator()()const&#39;:
main.cpp :(。text._ZNK3FooclEv [_ZNK3FooclEv] + 0x1a):未定义引用`Foo :: BAR&#39;
collect2:错误:ld返回1退出状态
如果我使用以下语句,也会发生同样的事情(非常明显):
return std::min(zero, Foo::BAR);
以下示例的略微修改版本
这个编译没有错误,即使我仍然指的是BAR
成员:
#include <algorithm>
struct Foo {
static constexpr float BAR = .42;
float operator()() const noexcept {
float zero = .0;
float bar = BAR;
return std::min(zero, bar);
}
};
int main() {
Foo foo;
foo();
}
我没有成功理解为什么后者版本编译得很好,而前者以错误结束。
据我所知,这两个版本都是正确的,应该编译,但我强烈怀疑我在这里缺少一些重要的东西。
有什么建议吗?
这是我的编译器版本:g++ (Debian 5.3.1-5) 5.3.1 20160101
。
答案 0 :(得分:4)
template<class T>
/* constexpr since C++14 */ const T& min( const T& a, const T& b );
的所选原型是
static constexpr float BAR = .42;
相关的一点是它通过引用获取参数,意味着它使用单一定义规则(ODR)。
你从来没有定义它,你只在你的类中声明它(使用初始化器):
{{1}}
这对于复制和使用该值是否足够好,但不能将其用作除prvalue之外的任何值。
请参阅Why does constexpr static member (of type class) require a definition?
违反ODR(其中的细节确实很好且很长)不需要诊断出来:
3.2一个定义规则 [basic.def.odr]
4每个程序应包含每个非内联函数或变量使用的变量的一个定义 在该计划中;无需诊断。定义可以在程序中明确显示,可以找到 在标准或用户定义的库中,或(在适当的时候)它是隐式定义的(见12.1,12.4和 12.8)。内联函数应在每个使用它的翻译单元中定义。