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;
}
The easiest way to check whether a function (e.g., foo ) is constexpr is to assign its return value to a constexpr as below: constexpr auto i = foo(); if the returned value is not constexpr compilation will fail.
Constexpr functions are implicitly inline, which means they are suitable to be defined in header files. Like any function in a header, the compiler is more likely to inline it than other functions.
A constexpr function is one whose return value is computable at compile time when consuming code requires it. Consuming code requires the return value at compile time to initialize a constexpr variable, or to provide a non-type template argument.
#define directives create macro substitution, while constexpr variables are special type of variables. They literally have nothing in common beside the fact that before constexpr (or even const ) variables were available, macros were sometimes used when currently constexpr variable can be used.
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). [...]
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");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With