More C++ Idioms/ポリシーの複製(Policy Clone)

ポリシーの複製(Policy Clone)
編集

意図 編集

ポリシークラスの型に対するアドホックな制限なしに無数の異なる可能な型でポリシークラスをインスタンス化する。

別名 編集

メタ関数ラッパイディオム(Meta-function wrapper idiom)

動機 編集

高度に再利用可能、柔軟で拡張可能なクラスはポリシーに基づくクラス設計テクニックを用いることで構築可能である[1]。ポリシーのホストクラスが、あるポリシーの正確な複製だが異なる型パラメータによってインスタンス化されたものを必要とすることがある。残念ながらホストクラステンプレートの作成者は、インスタンス化するそのテンプレート名を事前に知らない。その上、そもそもポリシークラスはテンプレートかもしれないし、テンプレートでないかもしれない。もしテンプレートであるならば、ホストクラスはパラメータ化されたポリシークラスをインスタンス化するのに必要な最少の型パラメータ数を知ることができない。もしテンプレートでないならば、ポリシークラスとして用いることができない。この状況は、作成するオブジェクトの型があらかじめ分からない場合の Factory Method (GoF) パターンの状況に非常に類似している。

template <class Apolicy>
class Host
{
  Apolicy direct_policy_use;
  Apolicy <SomeInternalType> InternalClone;  // 問題1: これは不可能
};

template <class T, template <class T> class Apolicy>
class Host2
{
  Apolicy <T> common_use;  
  Apolicy <SomeInternalType> InternalClone;  
  // これは可能だが、
  // 問題2: 2つ以上の型パラメータを必要とするポリシーが利用できない
};

解法とサンプルコード 編集

(rebind と呼ばれる)メンバテンプレート構造体を、ポリシークラステンプレートに異なる型パラメータを渡すために用いる。例えば、

template <typename T>
class NiftyAlloc
{
  public:
    template <typename Other>
    struct rebind // ポリシーの複製(The Policy Clone idiom)
    { 
       typedef NiftyAlloc <Other> other;
    };
    //...
};

template <typename T, class Alloc = NiftyAlloc <T> >
 where HasRebind <Alloc> // コンセプト: C++0x にのみ存在
class Vector 
{
  public:
    typedef typename Alloc::template rebind<long>::other ClonePolicy;
    // ここで、Alloc はテンプレートクラスでなくともよいし、あるいはパラメータ化された
    // 未知の個数の型パラメータをとるクラスのインスタンス化でもよい
};

ここで、Vector テンプレートは long 型によってインスタンス化された割り当てポリシー Alloc の複製を必要とする。そのため、NifyAlloc ポリシーによって公開された rebind 機構を用いる。型 Alloc::template rebind<long>::other は NiftyAlloc<long> と同じである。基本的には「この型がどのような種類のアロケータであるかも知らないし、それが何を割り当てるかも知らないが、long を割り当てるようなアロケータが欲しい」と言う記述になる。C++0x で導入される「コンセプト」を用いれば、Alloc ポリシー型が rebind コンセプトをサポートしているかどうかをチェックする型コンセプトを、Vector クラスに書くことが出来る。

コンパイラのために、ClonePolicy の typedef 内で typename と template の両方のキーワードを用いる必要がある。その用法は以下の通りである。もしメンバテンプレートの特殊化の名前が、., ->, :: 演算子の後に表れ、かつ、その名前が明示的にテンプレートパラメータによって修飾されている場合、メンバテンプレート名の前にキーワード template を置く。キーワード typename も必要である。なぜなら、"other" は型であって変数ではないからである。

既知の利用 編集

  • Standard Template Library
  • テンプレートテンプレートパラメータをサポートしないコンパイラ

関連するイディオム 編集

メタ関数ラッパイディオム(Meta-function wrapper idiom)はポリシーの複製より強力なイディオムである。ポリシーの複製イディオムはメタ関数ラッパよりも抽象的な方法でその目的を示している。rebind テンプレートは本質的にメタ関数ラッパである。

References 編集