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
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 aconstexpr
function. Similarly, aconstexpr
specifier used in a constructor declaration declares that constructor to be aconstexpr
constructor.constexpr
functions andconstexpr
constructors 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