18

When I attempt compiling the following code I get a linker error: Undefined symbols for architecture x86_64: "Foo()", referenced from: _main in main.o using LLVM 4.2.

This behavior only occurs when the function is marked constexpr. The program compiles and links correctly when the function is marked const. Why does declaring the function constexpr cause a linker error?

(I realize that writing the function this way doesn't give the benefit of compile-time computation; at this point I am curious why the function fails to link.)

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;
}
Aurelius
  • 11,111
  • 3
  • 52
  • 69

3 Answers3

14

Why does declaring the function constexpr cause a linker error?

That is because constexpr functions are implicitly inline. Per Paragraph 7.1.5/2 of the C++11 Standard:

A constexpr specifier used in the declaration of a function that is not a constructor declares that function to be a constexpr function. Similarly, a constexpr specifier used in a constructor declaration declares that constructor to be a constexpr constructor. constexpr functions and constexpr constructors are implicitly inline (7.1.2).

Per Paragraph 7.1.2/4, then:

An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case (3.2). [...]

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • 1
    `inline` doesn't have any effect on linkage. (It's likely that `constexpr` does, given its relationship with const in general, but there's nothing in the section that you quote which would indicate this.) – James Kanze Apr 25 '13 at 16:15
  • @JamesKanze: 7.1.5 says "The `constexpr` specifier has no effect on the type of a constexpr function or a constexpr constructor." and (language) linkage is part of a function's type (7.5). So that would seem to restrict any effect of `constexpr` on linkage. – Ben Voigt Jan 27 '16 at 16:57
  • @BenVoigt language linkage (`extern "C"`/`extern "C++"` etc.) and linkage (external/internal/no linkage) are completely different things. That said, `constexpr` doesn't affect the linkage of functions; it may affect the linkage of objects (due the the implicit `const`). – T.C. Jan 27 '16 at 17:01
11

The body of a constexpr function must be visible at every point where it's used. In your case you have to move Foo()'s code to test.hpp.

For instance, consider this code in main.cpp:

constexpr int Foo(); 

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

where Foo() is defined in test.cpp. How the compiler is supposed to check the static_assert condition while processing main.cpp if it cannot see that Foo() does return 42. That's impossible. The whole point of constexpr functions is that the compiler can "call" them at compile time and for this to happen it must see the code.

Therefore, this compiles fine:

constexpr int Foo() { return 42; }

int main() {
  static_assert(Foo() == 42, "Ops");
}
Cassio Neri
  • 19,583
  • 7
  • 46
  • 68
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();).

James Kanze
  • 150,581
  • 18
  • 184
  • 329