テンプレートの概要
パラメーター化された型とも呼ばれるテンプレートは、関数とクラスを型パラメーターに基づいて生成するための機構です。テンプレートを使用することで、型ごとに異なるクラスを作成する必要がなくなり、多くの型のデータを操作する単一のクラスまたは関数をデザインできます。
解説
たとえば、テンプレートを使用せずに 2 つ以上のパラメーターを返すタイプセーフな関数を作成するには、次のようなオーバーロード関数のセットを作成します。
// what_are_templates1.cpp
// compile with: /c
// min for ints
int min( int a, int b ) {
return ( a < b ) ? a : b;
}
// min for longs
long min( long a, long b ) {
return ( a < b ) ? a : b;
}
// min for chars
char min( char a, char b ) {
return ( a < b ) ? a : b;
}
テンプレートを使用して、この重複を単一の関数テンプレートに減らすことができます。
// what_are_templates2.cpp
// compile with: /c
template <class T> T min( T a, T b ) {
return ( a < b ) ? a : b;
}
テンプレートにより、タイプ セーフを損なうことなく、ソース コードのサイズを大幅に減らし、コードの柔軟性を向上させることができます。
テンプレートには、主に関数テンプレートとクラス テンプレートの 2 つの種類があります。前の例では、min は関数テンプレートです。クラス テンプレートは、以下のようなパラメーターを持つクラスです。
// what_are_templates3.cpp
template <class T> class A {
T m_t;
public:
A(T t): m_t(t) {}
void f(T t);
};
int main() {
A<int> a(10);
}
テンプレートは、いくつかの大きな相違点はありますが、他の関数やクラスのように宣言され、定義されます。テンプレート宣言は関数またはクラスを完全に定義できません。これは、クラスや関数の構文のスケルトンのみを定義します。実際のクラスまたは関数は、インスタンス化と呼ばれるプロセスでテンプレートから作成されます。作成される個々のクラスまたは関数は、インスタンス化と呼ばれます。たとえば、クラス テンプレートは次のようになります。
template <class T> struct A { . . . };
A<int>、A<char>、A<int*>、A<MyClass*> などのクラスのインスタンスの作成に使用できます。
クラスまたは関数のインスタンス化は明示的または暗黙的に行うことができます。明示的なインスタンス化は、生成するテンプレートのバージョンをコード内で呼び出す方法です。暗黙的なインスタンス化では、テンプレートが最初に使用された時点で必要に応じてインスタンス化されます。
テンプレートには、値パラメーターでパラメーター化することもできます。その場合、テンプレート パラメーターは、関数に対するパラメーターのように宣言されます。浮動小数点型とクラス型は、値パラメーターとして使用できません。
// what_are_templates4.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
template <int i> class A {
int array[i];
public:
A() { memset(array, 0, i*sizeof(int)); }
};
int main() {
A<10> a;
}
テンプレートに関する一般的な問題は、汎用型のソリューションになる場合があり、同じコードがすべてのタイプに適用されることです。特定の型のテンプレートの動作をカスタマイズする場合、特殊化を使用できます。明示的な特殊化を使用すると、ジェネリック型ではなく特定の実際の型用にテンプレートを特殊化できます。クラス テンプレートは、部分的に特化することもできます。これは複数の型パラメーターを持つテンプレートがある場合に便利です。一部のパラメーターに関して動作をカスタマイズすることはありますが、すべてをカスタマイズすることはありません。部分的特殊化は、まだジェネリックであり、実際にインスタンス化されるクラスを生成するには、実際のテンプレート引数が必要です。