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 L
Why does declaring the function
constexprcause a linker error?
That is because constexpr functions are implicitly inline. Per Paragraph 7.1.5/2 of the C++11 Standard:
A
constexprspecifier used in the declaration of a function that is not a constructor declares that function to be aconstexprfunction. Similarly, aconstexprspecifier used in a constructor declaration declares that constructor to be aconstexprconstructor.constexprfunctions andconstexprconstructors are implicitlyinline(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). [...]
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();).
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");
}