static データメンバの初期化 - constexpr な場合とそうでない場合
constexpr の間違った使い方。 - C++でゲームプログラミング
この記事へのフォローです。
constexpr static データメンバの場合は、"コンパイル時定数である変数は、宣言と同時に初期化しなければならない" という原則にしたがって、
クラススコープの内側に初期化を書いてやります。
template<typename T> struct X { static constexpr T value = {}; }; template<typename T> constexpr T X<T>::value;
つまり、constexpr の場合は内側の宣言に初期化を書き、そうでない場合は外側に初期化を書かなければならない。
非常に面倒な仕様と思います。
なお Sprout C++ Library では、constexpr が使える場合とそうでない場合双方に対応するために、
SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_INNER および SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_OUTER という二つのマクロを使っています。
//#define SPROUT_CONFIG_DISABLE_CONSTEXPR /* constexpr を無効にするかどうかのオプション。通常はコンパイラに応じて自動的に定義される */ #include <sprout/config.hpp> template<typename T> struct X { SPROUT_STATIC_CONSTEXPR T value SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_INNER({}); // constexpr が有効な場合はこちらで初期化される }; template<typename T> SPROUT_CONSTEXPR_OR_CONST T X<T>::value SPROUT_STATIC_CONSTEXPR_DATA_MEMBER_OUTER({}); // constexpr が無効な場合はこちらで初期化される
見てのとおり非常に面倒です。
C++03コンパイラ をターゲットにしなくてよい開発ならば、全部 constexpr で統一すればよいと思います。
Ceterum autem censeo, VC++ esse delendam. (ともあれ、VC++は滅ぶべきであると考える次第である)