静态constexpr成员似乎不支持std::min

Static constexpr members seem not to go along with std::min

本文关键字:std min 不支持 constexpr 成员 静态      更新时间:2023-10-16

这里有一个问题,原因我很不清楚,但幸运的是,解决方法很容易。

考虑以下代码(让我称之为我的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++11main.cpp
/tmp/ccjULTPy.o:在函数"Foo::operator()const"中:
main.cpp:(.text._ZNK3FooclEv[_ZNK3FooclEv]+0x1a):对"Foo::BAR"的未定义引用
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

min的选定原型是

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

相关的一点是,它引用了参数,这意味着它使用了一个定义规则(ODR)。
你从来没有定义过它,你只在你的类中声明了它(用初始化器):

    static constexpr float BAR = .42;

这对于复制和以其他方式使用该值来说已经足够好了,但对于将其用作prvalue之外的任何东西来说都不够好。

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

违反ODR(其细点确实很细且体积很大)无需诊断:

3.2一个定义规则

4每个程序应包含odr使用的每个非内联函数或变量的一个定义在该项目中;无需诊断。定义可以显式显示在程序中,可以找到在标准或用户定义的库中,或(在适当的情况下)隐式定义(见12.1、12.4和12.8).内联函数应在使用它的每个翻译单元中定义。