这里有一个问题,它的原因对我来说相当模糊,但是解决它的方法非常简单。
考虑下面的代码(让我称之为我的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: 在函数 'Foo::operator()() const' 中:
main.cpp:(.text._ZNK3FooclEv[_ZNK3FooclEv]+0x1a): 对 `Foo::BAR' 未定义的引用
collect2: error: 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
。
std::min
通过引用传递参数,ODR使用静态成员,您需要相应的定义。 - Piotr Skotnickiconstexpr
成员,但是没有定义它。然而,要将其传递给std::min
,它必须具有地址(因为它是通过引用进行传递的)。如果您仅将其值分配给局部变量,则它是左值到右值转换,这不会ODR使用静态数据成员,因此可以工作。 - Piotr Skotnicki