テンプレートの仕様
template 宣言は、一連のパラメーター化されたクラスまたは関数を指定します。
template < template-parameter-list > declaration
解説
template-parameter-list はテンプレート パラメーターのコンマ区切りのリストです。これは、テンプレート本体で使用される型 (class identifier、typename identifier、または template < template-parameter-list > class identifier の形式) または非型パラメーターです。 テンプレート パラメーターの構文は次のいずれかです。
parameter-declaration
class identifier [ = typename ]
typename identifier [ = typename ]
template < template-parameter-list > class [identifier][= name]
通常のクラスをインスタンス化するのと同様に、クラス テンプレートをインスタンス化できますが、テンプレート引数を山かっこ (<>) で囲む必要があります。 これらのテンプレート引数は、テンプレート引数リストにクラスまたは typename キーワードが含まれる場合は任意の型、引数が非型引数である場合は適切な型の値にできます。 関数テンプレートを呼び出すために必要な特別な構文はありませんが、関数の引数からテンプレート パラメーターを推測できない場合、山かっことテンプレート引数が必要になることがあります。
template-parameter-list は、後に続くコードのどの部分が変化するかを指定するテンプレート関数で使用されるパラメーターのリストです。 次に例を示します。
template< class T, int i > class MyStack...
この場合、テンプレートは 1 つの型 (class T) と定数パラメーター (int i) を受け取ることができます。 テンプレートは、インスタンス化で型 T と定数整数 i を使用します。 MyStack 宣言の本体で、T 識別子を参照する必要があります。
テンプレート宣言自体はコードを生成せず、クラスや関数のファミリを指定します。それらが他のコードによって参照されたときに、1 つまたは複数のクラスや関数が生成されます。
テンプレート宣言は、グローバル スコープ、名前空間スコープ、またはクラス スコープを持ちます。 これらは、関数の内部で宣言することはできません。
次の例は、型パラメーター T と非型テンプレート パラメーター i を持つクラス テンプレートの定義、宣言、およびインスタンス化を示しています。
// template_specifications1.cpp
template <class T, int i> class TestClass
{
public:
char buffer[i];
T testFunc(T* p1 );
};
template <class T, int i>
T TestClass<T,i>::testFunc(T* p1)
{
return *(p1++)
};
// To create an instance of TestClass
TestClass<char, 5> ClassInst;
int main()
{
}
非型テンプレート引数
非型テンプレート パラメーターは、整数、列挙体、ポインター、参照、またはメンバー型へのポインターである必要があり、コンパイル時には定数である必要があります。 これらは const または volatile 型として指定できます。 浮動小数点値は、テンプレート パラメーターとして使用できません。 クラス、構造体、または共用体型のオブジェクトは非型テンプレート パラメーターとして使用できません。ただし、これらのオブジェクトへのポインターは使用できます。 非型テンプレート パラメーターとして渡された配列はポインターに変換されます。 非型パラメーターとして渡された関数は、関数ポインターとして扱われます。 文字列リテラルは、テンプレート パラメーターとして許可されません。
テンプレート宣言での typename の使用
typename キーワードは、テンプレート パラメーター リストで利用できます。 次のテンプレート宣言は同じです。
template< class T1, class T2 > class X...
template< typename T1, typename T2 > class X...
テンプレート パラメーターの既定の引数
クラス テンプレートには、既定の引数を設定できます。指定するには、= 記号を使用し、その後に既定の型または値を続けます。 関数テンプレートには、既定の引数を指定できません。 詳細については、「クラス テンプレートの既定の引数」を参照してください。
template<typename Type> class allocator {};
template<typename Type,
typename Allocator = allocator<Type> > class stack
{
};
stack<int> MyStack;
テンプレート パラメーターの再利用
テンプレート パラメーターは、テンプレート パラメーター リスト内で再利用できます。 たとえば、次のようなコードを記述できます。
// template_specifications2.cpp
class Y
{
};
template<class T, T* pT> class X1
{
};
template<class T1, class T2 = T1> class X2
{
};
Y aY;
X1<Y, &aY> x1;
X2<int> x2;
int main()
{
}
テンプレート パラメーターとしてのテンプレート
テンプレート パラメーターは、それ自体がテンプレートである可能性があります。 この構造では、引数自体がテンプレートであり、テンプレートから構築されたクラスであってはなりません。 次の例では、使用されることがありえないため、テンプレートのテンプレート パラメーターの名前 A は省略できます。
// template_specifications3.cpp
#include <stdio.h>
template <class T> struct str1
{
T t;
};
template <template<class A> class T> struct str2
{
T<int> t;
};
int main()
{
str2<str1> mystr2;
mystr2.t.t = 5;
printf_s("%d\n", mystr2.t.t);
}
出力
5
テンプレート パラメーターとしての参照
Visual Studio .NET 2003 では、非型テンプレート パラメーターとして参照を使用する機能が導入されました。 これは、以前のバージョンでは許可されていませんでした。
// references__supported_as_nontype_template_parameters.cpp
#include <stdio.h>
extern "C" int printf_s(const char*,...);
template <int & ri> struct S
{
S()
{
printf_s("ri is %d\n", ri);
}
~S()
{
printf_s("ri is %d\n", ri);
}
};
int i = 1;
int main()
{
S<i> s;
i = 0;
}
出力
ri is 1
ri is 0
入れ子になったテンプレート インスタンス
Visual Studio 2005 より前のバージョンの Visual Studio では、入れ子になったテンプレート インスタンスの宣言時に、テンプレート パラメーター リストの間に空白を挿入する必要がありました。 次の構文が許されるようになりました。
// template_specifications4.cpp
template <typename T>
class A
{
};
template <int n>
class B
{
};
int main()
{
A<B<22>>();
}