クラステンプレートの型パラメータに対してのみ可能な暗黙の型変換(coercion)と
同じ型変換を、テンプレートクラスに対して行うことを可能にすることによって、
クラステンプレートのインタフェースの自由度を向上させる。
ある 2 つの型の関係を、それらの型によってインスタンス化されたテンプレートクラス型に対しても「拡張」することは
しばしば有益である。例えば、クラス D がクラス B から派生されているとしよう。その場合、D 型のオブジェクトへのポインタは、B 型へのポインタに代入可能である。これらの意味論は C++ 言語規格によって暗黙的にサポートされている。
残念ながら、これらの型の複合型は、その基となった型の関係を共有しない。このルールはテンプレートに対しても
同様に適用されるため、一般的には、Helper<D> は Helper<B> に代入可能ではない。
class B {};
class D : public B {};
template 
class Helper {};
B *bptr;
D *dptr;
bptr = dptr; // 規格によって認められている
Helper hb;
Helper hd; 
hb = hd; // これは認められていないが、非常に有益になりうる
このルールに対する例外を認めた方が、まったく例外を認めない場合よりも、より多くの利益と自由度を
もたらす場合がある。
例えば、auto_ptr<D> から auto_ptr<B> への変換は認めたいだろう。
これは非常に直感に即した挙動だが、メンバテンプレートによる型変換(coercion by member template)イディオムの利用なしには規格によってサポートされない。
クラステンプレート内で独立したメンバテンプレート関数を定義し、パラメータ型によってサポートされている
暗黙の型変換をメンバテンプレートの実装中で利用する。
template 
class Ptr
{
  public:
    Ptr () {}
    Ptr (Ptr const & p)
      : ptr (p.ptr)
    {
      std::cout << "これはコピーコンストラクタ\n";
    }
    // メンバテンプレートコンストラクタを利用して型変換(coercion)をサポートする
    template 
    Ptr (Ptr  const & p)
      : ptr (p.ptr) // U から T への暗黙の変換が認められていなければならない
    {
      std::cout << "変換に便利なメンバテンプレートコンストラクタは"
                   "コピーコンストラクタではない\n";
    }
    // メンバコピー代入演算子
    Ptr & operator = (Ptr const & p)
    {
      ptr = p.ptr;
      std::cout << "メンバコピー代入演算子\n";
      return *this;
    }
    // メンバテンプレート代入演算子を利用して型変換(coercion)をサポートする
    template 
    Ptr & operator = (Ptr  const & p)
    {
      ptr = p.ptr; // U から T への暗黙の変換が認められていなければならない
      std::cout << "変換に便利なメンバテンプレート代入演算子は"
                   "コピー代入演算子ではない\n";
      return *this;
    } 
    T *ptr;
};
int main (void)
{
   Ptr  d_ptr;
   Ptr  b_ptr (d_ptr); // もはや可能
   b_ptr = d_ptr;         // これもまた可能
}
クラス D がクラス B である (is-a の関係にある)としても、D 型オブジェクトの配列は B 型オブジェクトの配列ではない(is-a の関係にはない)。
これはスライシングの問題のために、C++ 規格によって認められていない。
このルールをポインタの配列に対してゆるめることは、きわめて頻繁に大きな自由度をもたらす。
例えば、D へのポインタの配列は、B へのポインタの配列に代入可能であるとよい。
このイディオムはそれを可能とする。ただし、派生型のオブジェクトの配列を、
基本型のオブジェクトの配列にコピーできないようにするよう格別の注意を払うべきである。
その実現に、メンバテンプレート関数の部分特殊化を用いることができる。以下の例では、U * に対する部分特殊化を
ポインタの配列のコピーのみを許すために使用している。
template 
class Array
{
  public:
    Array () {}
    Array (Array const & a)
    {
      std::copy (a.array_, a.array_ + SIZE, array_);
    }
    template 
    Array (Array  const & a)
    {
      std::copy (a.array_, a.array_ + SIZE, array_);
    }
    template 
    Array & operator = (Array  const & a)
    {
      std::copy (a.array_, a.array_ + SIZE, array_);
    }
    enum {  SIZE = 10 };
    T array_[SIZE];
};
標準の auto_ptr や boost の shared_ptr のように、多くのスマートポインタがこのイディオムを用いている。
メンバテンプレートによる型変換イディオムの実装における典型的な誤りは、
''非テンプレート版''を提供することなしに、テンプレートコピーコンストラクタやテンプレート代入演算子を
提供しようとすることである。
非テンプレート版が提供されていないならば、コンパイラは自動的に''デフォルト''のコピーコンストラクタと
コピー代入演算子の両方あるいは一方を生成するだろう。そして隠れた明白ではない障害を引き起こすかもしれない。
More_C++_Idioms/Coercion by Member Template
|めんはてんふれーとによるかたへんかん]]