静态 constexpr 成员似乎不符合 std::min

sky*_*ack 4 c++ static stl-algorithm constexpr c++11

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

考虑以下代码(让我称其为 my 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();
}
Run Code Online (Sandbox Code Playgroud)

当我尝试编译它时,出现错误:

foob​​ar:~/stackoverflow$ g++ -std=c++11 main.cpp
/tmp/ccjULTPy.o: 在函数 'Foo::operator()() const':
main.cpp:(.text._ZNK3FooclEv[_ZNK3FooclEv] +0x1a):对‘Foo::BAR’的未定义引用
collect2:错误:ld 返回 1 个退出状态

如果我使用以下语句,也会发生同样的情况(很明显):

return std::min(zero, Foo::BAR);
Run Code Online (Sandbox Code Playgroud)

下面是上面示例的稍微修改的版本。
这个编译没有错误,即使我仍然指的是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();
}
Run Code Online (Sandbox Code Playgroud)

我没有成功理解为什么后一个版本编译得很好,而前一个版本以错误结束。
据我所知,这两个版本都是正确的,应该可以编译,但我强烈怀疑我在这里遗漏了一些重要的东西。

有什么建议吗?

这是我的编译器版本:g++ (Debian 5.3.1-5) 5.3.1 20160101.

Ded*_*tor 5

所选择的原型为minIS

template<class T> 
/* constexpr since C++14 */ const T& min( const T& a, const T& b );
Run Code Online (Sandbox Code Playgroud)

相关的一点是它通过引用获取参数,这意味着它使用单一定义规则 (ODR)。
而且您从未定义过它,您只是在您的类中声明了它(使用初始化程序):

    static constexpr float BAR = .42;
Run Code Online (Sandbox Code Playgroud)

这对于复制和以其他方式使用该值已经足够了,但不能将它用作除纯右值之外的任何东西。

请参阅为什么 constexpr 静态成员(类类型)需要定义?

不需要诊断违反 ODR(其更精细的点确实很细且数量庞大):

3.2 一个定义规则[basic.def.odr]

4 每个程序都应包含该程序中 odr 使用的每个非内联函数或变量的一个定义;无需诊断。定义可以显式地出现在程序中,可以在标准或用户定义的库中找到,或者(在适当的时候)它是隐式定义的(参见 12.1、12.4 和 12.8)。内联函数应在每个使用 odr 的翻译单元中定义。