boost::enable_ifを特殊化する(後編)

上の問題はOtherTからTへの暗黙の変換がない場合でも,第2引数の型が存在することが原因でした.そこで,OtherTからTへの暗黙の変換が存在しない場合に存在しないような型を定義してやれば良いことになります.
方法は私が知っている範囲で2つあります.
第1の方法はenable_if_convertible自体を存在しない型にする方法です.このために,enable_if_convertibleの定義においてboost::enable_ifを使ってみます.

template<class T1, class T2,
  class T3 = typename boost::enable_if >::type>
struct enable_if_convertible{};

これを使って,問題のコンストラクタテンプレートは以下のように書けます.

template
C(C const &r, enable_if_convertible * = 0)
  : v(r.v){}

この方法はtypenameキーワードが不要になり,SFINAEのためのダミー引数をさらに短く記述できるので(゜д゜)ウマーです.もちろん,これはis_convertibleともうまく連携します.
もう一つ,方法があります.

template
struct enable_if_convertible
  : public boost::enable_if >
{};

こちらは以下のように使えます.

template
C(C const &r,
  typename enable_if_convertible::type * = 0)
  : v(r.v){}

こちらはさきほどより長くなりますが,boost::enable_ifの記述に沿った形式なのでこれはこれで(゜д゜)ウマーだと思われます.
実は後者のような,継承を利用してenable_ifを特殊化し,それを別名で定義する方法は自分で思いついたものではなくて,実際にboostのコードでこのような使われ方をしているのを発見したものです.メタ関数として使われるクラスは実行時に多相的に使われることをまったく意図していないと思われるので,このような継承の使い方は安全であると判断できると思います.
最後に上のコードをまとめたものを掲載しておきます.(要boost1.31.0.VC++7.1で動作確認済み)

#include 
#include 
#include 

template
struct enable_if_convertible
  : public boost::enable_if >
{};

template
class C{
  template friend class C;

public:
  C(T const &val = T())
    : v(val){}

  C(C const &r)
    : v(r.v){}

  template
  C(C const &r, 
  typename enable_if_convertible::type * = 0)
    : v(r.v){}

private:
  T v;
};

int main(int argc, char *argv[])
{
  C a;
  C b(a);

  std::cout << boost::is_convertible, C >::value << std::endl;
  std::cout << boost::is_convertible, C >::value << std::endl;

  return 0;
}