constexpr函数的未定义符号

时间:2013-04-25 16:09:14

标签: c++ c++11 linker-errors constexpr

当我尝试编译以下代码时,我得到一个链接器错误: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;
}

3 个答案:

答案 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();)完全相同。