91

I have a class Dimension which I defined (like all my classes) in a file Dimension.h:

class Dimension
{
public:

    constexpr Dimension() noexcept;

    constexpr Dimension(int w, int h) noexcept;

    int width;
    int height;

};

I thought I could, like in all my classes, put the definition in a separate Dimension.cpp:

#include "Dimension.h"

constexpr Dimension::Dimension() noexcept : width(0), height(0) {}

constexpr Dimension::Dimension(int w, int h) noexcept : width(w), height(h) {}

But when I try to use the class, the compiler tells me:

warning: inline function 'constexpr Dimension::Dimension()' used but never defined

and while linking:

undefined reference to 'pong::graphics::Dimension::Dimension()'

(same with the other constructor)

If I define the class in the header like so:

class Dimension
{
public:

    constexpr Dimension() noexcept : width(0), height(0) {}

    constexpr Dimension(int w, int h) noexcept : width(w), height(h) {}

    int width;
    int height;

};

and omit the .cpp file, everything works fine.

I'm using GCC 4.9.2. Why does separate definition not work?

zerocukor287
  • 555
  • 2
  • 8
  • 23
Timo Türschmann
  • 4,388
  • 1
  • 22
  • 30
  • 9
    The whole point of a `constexpr` function is to allow evaluating the function at compile time. Which would be rather difficult to pull off if the compiler cannot see the body of said function. – Igor Tandetnik Dec 07 '14 at 17:13
  • I already suspected that, but I'm not quite sure if I can explain (with references maybe) why it happens exactly. I did not find anything about this while googling, so I figured a new question for this was appropriate. – Timo Türschmann Dec 07 '14 at 17:19
  • 1
    _@TimoTürschmann_ _"but I'm not quite sure if I can explain (with references maybe) why it happens ..."_ To reword @IgorTandetnik 's comment a bit: The compiler needs to see a `constexpr` hcompletely expanded whenever it's used, to insert the correct expression in place. Linking stage is too late. – πάντα ῥεῖ Dec 07 '14 at 17:25
  • 6
    If you insist on chapter and verse: **7.1.5/2** `constexpr` functions and `constexpr` constructors are implicitly inline. **3.2/4** An inline function shall be defined in every translation unit in which it is odr-used. – Igor Tandetnik Dec 07 '14 at 17:36

2 Answers2

99

If a constexpr function is not defined inside the header, the compiler can not see the definition of the constexpr functions while compiling all the other source files.

Obviously, if it can't see the definition of the functions, it can't perform the steps necessary to calculate them at compile-time. Thus all constexpr functions must be defined everywhere they are used.

Thanks @IgorTandetnik:
[dcl.constexpr] §7.1.5/2

constexpr functions and constexpr constructors are implicitly inline.

[basic.def.odr] §3.2/4

An inline function shall be defined in every translation unit in which it is odr-used.

Kai Ninomiya
  • 156
  • 2
  • 6
Timo Türschmann
  • 4,388
  • 1
  • 22
  • 30
24

What you're asking can be accomplished, with a significant limitation: the constexpr function can then only be called from inside the translation unit (i.e. source file) where it is defined. This is not appropriate for the example you gave, since the constructor is meant to be part of the class' public interface. However it can be very useful in other cases, e.g. to define private methods as constexpr and then use their return values in expressions that need to be known at compile time, e.g. template instantiations, switch statement labels, etc.

Isac Casapu
  • 1,163
  • 13
  • 21
  • It was very confusing reading the first answer and then looking at compiling source code where there are constexpr functions defined in both .h and .cpp files. The accepted solution above is actually incorrect by omitting this essential detail. – okovko Jun 20 '22 at 18:46
  • @okovko The accepted solution says "all constexpr functions must be defined everywhere they are used." That's your "essential detail". – Matthew M. Oct 25 '22 at 17:37