Undefined reference error for static constexpr member

y0prst picture y0prst · Nov 19, 2016 · Viewed 9.7k times · Source

Consider this code:

#include <vector>

struct A {
  static constexpr int kDefaultValue = -1;
  std::vector<int> v;
  A(int n): v(n, A::kDefaultValue) {}
};

int main() {
  A(10);
  return 0;
}

It fails to link (llvm clang, gcc 4.9, both on OS X):

Undefined symbols for architecture x86_64:
  "A::kDefaultValue", referenced from:
      A::(int) in main.cpp.o
ld: symbol(s) not found for architecture x86_64

The question is what's wrong with it? It can be fixed by static_cast-ing A::kDefaultValue to int. Or by moving kDefaultValue out of A. Both cases seem to be ugly. Is this another way to make it link?

Answer

Walter picture Walter · Nov 19, 2016

This behaviour is vexing me time and again. The cause of the trouble is that your

A(int n): v(n, A::kDefaultValue) {}

odr-uses the static constexpr member, since the constructor of v takes a constant reference second argument. Odr-usage requires a definition somewhere, i.e.

const int A::kDefaultValue;

in some compilation unit (which is compiled and linked to main()). This requirement has been dropped in C++17 and the corresponding definition (as above) deprecated.

However, a definition is not always possible (for example for members of class templates) and the simplest way to avoid both the definition and your error is

A(int n): v(n, int(A::kDefaultValue)) {}

which creates a temporary to be passed to the constructor of v (but since the latter is fully inline, the compiler may optimise that away).