17

当我尝试编译以下代码时,出现链接器错误:Undefined symbols for architecture x86_64: "Foo()", referenced from: _main in main.o使用 LLVM 4.2。

此行为仅在函数被标记时发生constexpr。当函数被标记时,程序编译和链接正确const。为什么声明函数constexpr会导致链接器错误?

(我意识到以这种方式编写函数并没有带来编译时计算的好处;此时我很好奇为什么函数无法链接。)

主文件

#include <iostream>
#include "test.hpp"

int main()
{
    int bar = Foo();
    std::cout << bar << std::endl;

    return 0;
}

测试.hpp

constexpr int Foo();

测试.cpp

#include "test.hpp"

constexpr int Foo()
{
    return 42;
}
4

3 回答 3

14

为什么声明函数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)。[...]

于 2013-04-25T16:12:21.663 回答
11

函数的主体constexpr必须在使用它的每个点都可见。在您的情况下,您必须将move Foo()代码转换为test.hpp.

例如,考虑以下代码main.cpp

constexpr int Foo(); 

int main() {
  static_assert(Foo() == 42, "Ops");
}

其中在Foo()中定义test.cpp。如果编译器看不到返回,则应该如何static_assert在处理时检查条件。这不可能。函数的全部意义在于编译器可以在编译时“调用”它们,为此它必须查看代码。main.cppFoo()42constexpr

因此,这编译得很好:

constexpr int Foo() { return 42; }

int main() {
  static_assert(Foo() == 42, "Ops");
}
于 2013-04-25T16:26:22.713 回答
1

It's an interesting question. As Andy Prowl, constexpr makes the function inline, which means that there must be a definition of it in every translation unit which uses it; I would have expected an error from the compiler. (Actually, if I read §3.2/5 correctly, a diagnostic is required if you use the function and there is no definition.)

As to why const has different behavior: you can't mark a non-menber function const. If you write const int Foo();, it is not the function which is const, but the type it returns (except that if the return type is not a class type, cv-qualifiers are ignored, so this is really the same as int Foo();).

于 2013-04-25T16:24:14.337 回答