当我尝试编译以下代码时,我得到一个链接器错误:Undefined symbols for architecture x86_64: "Foo()", referenced from: _main in main.o
使用LLVM 4.2。
仅当函数标记为constexpr
时才会出现此行为。当函数标记为const
时,程序会正确编译和链接。为什么声明函数constexpr
会导致链接器错误?
(我意识到以这种方式编写函数不会带来编译时计算的好处;此时我很好奇为什么函数无法链接。)
的main.cpp
#include <iostream>
#include "test.hpp"
int main()
{
int bar = Foo();
std::cout << bar << std::endl;
return 0;
}
test.hpp
constexpr int Foo();
TEST.CPP
#include "test.hpp"
constexpr int Foo()
{
return 42;
}
答案 0 :(得分:10)
为什么声明函数
constexpr
会导致链接器错误?
这是因为constexpr
函数隐含inline
。根据C ++ 11标准的第7.1.5 / 2段:
在函数声明中使用的
constexpr
说明符不是构造函数声明该函数 成为constexpr
函数。类似地,构造函数声明中使用的constexpr
说明符声明了这一点 构造函数是constexpr
构造函数。constexpr
函数和constexpr
构造函数是隐式的inline
(7.1.2)。
按照第7.1.2 / 4段,然后:
内联函数应在每个使用过的翻译单元中定义,并且应具有确切的内容 在每种情况下(3.2)都有相同的定义。 [...]
答案 1 :(得分:7)
constexpr
函数的主体必须在每个使用它的位置都可见。在您的情况下,您必须move Foo()
的代码test.hpp
。
例如,请考虑main.cpp
中的此代码:
constexpr int Foo();
int main() {
static_assert(Foo() == 42, "Ops");
}
其中Foo()
在test.cpp
中定义。如果编译器看不到static_assert
确实返回main.cpp
,则在处理Foo()
时如何检查42
条件。这不可能。 constexpr
函数的重点是编译器可以在编译时“调用”它们,为此必须看到代码。
因此,编译很好:
constexpr int Foo() { return 42; }
int main() {
static_assert(Foo() == 42, "Ops");
}
答案 2 :(得分:1)
这是一个有趣的问题。正如Andy Prowl,constexpr
所做的那样
函数inline
,这意味着必须有
每个使用它的翻译单位的定义;
我原本期望编译器出错。 (实际上,如果
我正确阅读§3.2/ 5,如果您使用,则需要诊断
功能,没有定义。)
至于为什么const
有不同的行为:你无法标记
非义务函数const
。如果你写const int Foo();
,
它不是const
的函数,而是它返回的类型
(除非返回类型不是类类型,
cv-qualifiers被忽略,因此这与int
Foo();
)完全相同。