Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undefined symbols for constexpr function

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;
}
like image 963
Aurelius Avatar asked Apr 25 '13 16:04

Aurelius


People also ask

How do I know if a function is constexpr?

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.

Do constexpr functions have to be defined in header?

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.

What are constexpr 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.

Why constexpr instead of define?

#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.


2 Answers

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). [...]

like image 67
Andy Prowl Avatar answered Oct 20 '22 09:10

Andy Prowl


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");
}
like image 11
Cassio Neri Avatar answered Oct 20 '22 10:10

Cassio Neri