静的なメンバ定数を参照するとリンクエラーとなる

クラス内にstatic constexpr Tで宣言した定数を、std::vector::emplace_back()関数とかに渡すと、リンクエラーになる場合があります。

ミニマムなコードとしては、以下のようになります:

struct X {
    static constexpr int x = 3;
};

template <class T>
void f(T&&) {}

int main()
{
    f(X::x); // リンクエラー : X::xの実体が見つからない
}

クラスの静的定数は、宣言だけした場合にコピーはできますが、その変数のポインタや参照をとったりはできません。そのようなことをしたい場合は、どこかの.cpp/.ccといった拡張子のソースファイルで、変数を定義する必要があります。

struct X {
    static constexpr int x = 3;
};

template <class T>
void f(T&&) {}

constexpr int X::x; // この翻訳単位にX::xの実体を置く
int main()
{
    f(X::x); // OK
}

回避策として考えられるのは、以下のようなものです:

  • C++17のインライン変数で定数を定義する (staticメンバ変数は自動的にインラインになる)
  • constexpr変数ではなく、constexpr関数で定数を定義する

参照