特殊化のすゝめ

テンプレートの特殊化

今回は前回に引き続き簡単なテンプレートについてです!
簡単なことばかりだけどまだ始めたばかりだから許してねー

テンプレートの特殊化とは?

型に依存しない処理を記述できるテンプレートなのですが、型によって処理を変えたい場合も少なからず出てきます。
そういた場合には特殊化という技術を使うことが出来ます。

template<typename T>
bool equal(T a, T b) { return a == b; }

template<>
bool equal(char* a, char* b) { return strcmp(a, b) == 0; }

今回は文字列の比較を行う場合にだけ処理を変える実装を記述しています。
このように特殊化とは基本となるテンプレートとは別に型を指定した処理を記述する技術の事です。

クラステンプレートの特殊化

上記では関数テンプレートで記述した特殊化ですが、勿論クラステンプレートでも行うことが出来ます。

template<typename T>
class TClass
{
public:
    TClass(void) { printf("template class"); }
};

template<>
class TClass<int>
{
public:
    TClass(void) { printf("template class int"); }
};

テンプレートの特殊化は様々な応用も出来る技術です、テンプレートを使う上ではとても重要な技術になります。

 

テンプレートの部分特殊化

今回は曖昧さを残したまま特殊化を行うテンプレートの部分特殊化について書いていきます。

部分特殊化の例
template<typename T>
bool IsPointer(T){ return false; }
template<typename T>
bool IsPointer(T*){ return true; }

int n = 0;
int* p = &n;
if( IsPointer(n) ) { printf("n is pointer"); }
if( IsPointer(p) ) { printf("p is pointer"); }

結果:p is pointer

このように部分的に内容を指定することにより型を確定させず特殊化を行うことが出来ます。
この技術のことをテンプレートの部分特殊化と呼びます。

部分特殊化による配列要素数の取得
template<typename T, int N>
int ArrayCount(const T (&)[N])
{
	return N;
}

int n[32];
printf("%d", ArrayCount(n));

結果:32

このように特殊化では型だけではなく値も取得することが出来ます。
そして配列の要素数だけを部分特殊化することによって配列の要素数を取得することが可能です。

部分特殊化による再帰処理
template<typename T>
void ArrayFill(T (&target), const T& value)	{ target = value; }

template<typename T, typename U, int N>
void ArrayFill(T (&target)[N], const U& value)
{
    for( u32 i=0; i < N; i++ )
    {
        ArrayFill(target[i], value);
    }
}

int n[8][8][8];
ArrayFill(n, 5);

テンプレートでは特殊化を使用して再帰処理的な記述を行うことが出来ます。
今回の例では部分特殊化により配列の要素を再帰的になめていくようになっており、
そして引数が配列ではない場合にのみ値を代入するようになっています。

こんな感じで部分特殊化を使用することでテンプレートの使い方にバリエーションが出てきます。
使い方次第ではあんなことやこんなことも!

というわけで今回はこんなところで終わりたいと思います!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です