静态constexpr成员似乎不喜欢std :: min

时间:2016-01-06 16:39:09

标签: c++ c++11 static constexpr stl-algorithm

这是一个问题,其原因对我来说相当模糊,但幸运的是,其解决方法很容易。

考虑以下代码(我将其称为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

1 个答案:

答案 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)。内联函数应在每个使用它的翻译单元中定义。