C++学習のテンプレート特例化


テンプレートはC++の重要な特性であり、ユーザー定義タイプを含む複数のデータ型にコードを書くことができます.たとえば、STLのsort()関数は、複数のデータ型のソートに使用でき、クラスstackは複数のデータ型のスタックとして使用できます.しかし、汎用テンプレートではなく、特定のデータ型に対して異なるコードを実行したい場合は、テンプレート特例化(template specialization)を使用します.
一、関数テンプレートの特例化
関数テンプレートを特例化する場合は、元のテンプレートの各テンプレートパラメータに実パラメータを指定する必要があります.キーワードtemplateの後に空のカッコ<>、すなわちtemplate <>を使用して、テンプレートを特例化していることを示します.
template <typename T>
void fun(T a)
{
	cout << "The main template fun(): " << a << endl;
}

template <>   //  int    
void fun(int a)
{
	cout << "Specialized template for int type: " << a << endl;
}

int main()
{
	fun<char>('a');
	fun<int>(10);
	fun<float>(9.15);
	return 0;
}

出力結果:
The main template fun(): a
Specialized template for int type: 10
The main template fun(): 9.15

int型を除く他のデータ型については、汎用バージョンの関数テンプレートfun(T a)が呼び出される.int型の場合、特例化バージョンのfun(int a)が呼び出されます.特例化されたバージョンの本質は、関数のリロードではなくインスタンスであることに注意してください.したがって,特例化は関数マッチングに影響しない.
二、クラステンプレートの特例化
特例化関数テンプレートに加えて、クラステンプレートを特例化することもできます.簡単な例を次に示します.
template <typename T>
class Test{
public:
	void print(){
		cout << "General template object" << endl;
	}
};

template<>   //  int    
class Test<int>{
public:
	void print(){
		cout << "Specialized template object" << endl;
	}
};

int main()
{
	Test<int> a;
	Test<char> b;
	Test<float> c;
	a.print();
	b.print();
	c.print();
	return 0;
}
出力結果:
Specialized template object
General template object
General template object
さらに、クラステンプレートの特例化は、関数テンプレートとは異なり、すべてのテンプレートパラメータに実パラメータを提供する必要はない.クラステンプレートと呼ばれるすべてのテンプレートパラメータではなく、一部のみを指定できます.
偏特化または
一部特例化(partial specialization).たとえば、C++標準ライブラリのクラスvectorの定義:
template <typename T, typename Allocator>
class vector
{
	/*......*/
};

//      
template <typename Allocator>
class vector<bool, Allocator>
{
	/*......*/
};
vectorの例では、
1つのパラメータはboolタイプにバインドされますが、もう1つのパラメータはバインドされていません.ユーザーが指定する必要があります.クラステンプレートの一部の特例化バージョンは依然として1つであることに注意してください.
ユーザーは、特例化されたバージョンで指定されていないテンプレートパラメータにも実パラメータを指定する必要があるため、テンプレートを使用します.