イントロ
通常のクラス同様、templateクラス内にも静的メンバ変数を用意することができる。しかし、その実体の用意の方法は特殊化の方法や有無によって異なる。少しハマってしまったので、覚書としてまとめておく。すでに知っていた人は、何を今頃、とでも思いながら眺めてください。
非templateクラス内の静的メンバ
比較のために、まず通常のクラス中での静的メンバ変数の宣言を書いてみる。
class Hoge{
static int Value;
};
#include "non_template_static_value.hpp"
int Hoge::Value=0;
staticメンバ変数の実体は、当然ソースファイルに別に記述する必要がある。
###templateクラス内での静的メンバ
次にtemplateクラス内で、静的メンバ変数を宣言した場合。
template<typename A>
class Hoge{
static int Value;
};
template<typename A>
int Hoge<A>::Value=0;
templateクラス内の静的メンバの場合には、template宣言template<typename A>
とともに静的メンバ変数の実体をヘッダファイル内に記述する。
明示的特殊化したクラス内での静的メンバ変数
さて、次にtemplateクラスを明示的特殊化したクラス内でのみ、静的メンバ変数を使いたい状況を考えてみる。
template<typename A>
class Hoge{
};
template<>
class Hoge<int>{
static int Value;
};
#include"explicit_specialization_static_value.hpp"
int Hoge<int>::Value=0;
明示的特殊化したクラスで宣言した変数の実体は、すでにint
で確定しているため、template非依存なので、静的メンバ変数の実体は非templateクラス同様template宣言なしで、ソースファイルに実体を用意する必要がある。
これは、スタックオーバーフローでの質問で初めて気づいた。回答者様、ありがとうございます。
部分的特殊化したクラス内の静的メンバ
同じ特殊化でも、部分的特殊化の場合には、また変わってくる。
template<typename A>
class Hoge{
};
template<typename A>
class Hoge<A*>{
static int Value;
};
template<typename A>
int Hoge<A*>::Value=0;
部分特殊化したクラスで宣言した変数の実体は、まだtemplate依存なので、通常のtemplateクラス同様、template宣言template<typename A>
とともにヘッダファイル内に静的メンバ変数の実体を記述する。
ネストされたtemplateの静的メンバ
templateが複数ネストされている場合も少しややこしい。
template<typename A>
class Hoge{
template<typename B>
class Fuga{
static int Value;
};
};
template<typename A>
template<typename B>
int Hoge<A>::Fuga<B>::Value=0;
templateがネストされている場合、変数の実体宣言時には、template宣言template<typename ???>
を必要なだけ重ねることで宣言できる。
結論
非templateクラスや、templateの明示的特殊化クラス内の静的メンバ変数
=> template宣言なしで、ソースに実体を用意
templateクラスや、templateの部分特殊化クラス内の静的メンバ変数
=> template宣言とともにヘッダで実体を用意
templateクラスがネストされている場合
=> 必要なだけtamplate宣言を重ねて、ヘッダに実体を用意