2相テンプレートを用いることで、ホストクラスから見て同一のインタフェースを持つポリシークラスの複数の実装に、異なる個数のテンプレートパラメータを持たせることができる。以下に例を示す。
例 5.9. 異なる個数のテンプレートパラメータを持つポリシークラス
template <typename T>
class allocation_policy_new_backend
{
protected:
void* allocate() { return ::operator new(sizeof(T)); }
void deallocate(void* p) throw() { ::operator delete(p); }
};
struct allocation_policy_new
{
template <typename T>
struct bind { typedef allocation_policy_new_backend<T> type; };
};
template <typename T, class EXP>
class allocation_policy_malloc_backend
{
private:
typedef EXP exception_type;
protected:
void* allocate() {
void* const p = std::malloc(sizeof(T));
if (!p) throw exception_type();
return p;
}
void deallocate(void* p) throw() { std::free(p); }
};
template <class EXP = std::bad_alloc>
struct allocation_policy_malloc
{
template <typename T>
struct bind { typedef allocation_policy_malloc_backend<T, EXP> type; };
};
template <typename T, class AP>
class container
: public AP::template bind<T>::type
{
private:
typedef typename AP::template bind<T>::type allocation_policy;
public:
// ...
};
void foo()
{
typedef int T;
typedef allocation_policy_new A;
typedef allocation_policy_malloc<> B;
typedef allocation_policy_malloc<myexception> C;
typedef container<T, A> C_A;
typedef container<T, B> C_B;
typedef container<T, C> C_C;
}
allocation_policy_newとallocation_policy_mallocは2相テンプレートを用いた割り当てポリシークラスである。両者のバックエンドのクラステンプレートは互いに異なる個数のテンプレートパラメータを取るが、どちらもcontainerのポリシークラスとして機能する。
クライアントコードfooにあるように、allocation_policy_newは、そのままホストクラスcontainerにテンプレートパラメータとして渡される。一方、allocation_policy_mallocは、まずフロントエンドのクラステンプレートがfoo内で実体化され、実体化後のクラスやallocation_policy_malloc<>がallocation_policy_malloc<myexception>containerにテンプレートパラメータとして渡される。
一般に、2相テンプレートを用いたポリシークラスは、ポリシークラスごとに任意の個数の追加のテンプレートパラメータを設けることができる。追加のテンプレートパラメータは、ホストクラスに渡される前にクライアントコード内で束縛される。一方、すべてのポリシークラスに共通のテンプレートパラメータは、ホストクラス内で束縛される。