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

さて,上のSFINAEで用いたenable_ifですが若干長ったらしいのが気になります.

typename boost::enable_if >::type

これを以下のように書けたら良いと思いませんか?

typename enable_if_convertible::type

まぁ,この程度ならさほど(というかほとんど)必要を感じませんが,より複雑なSFINAEの条件を書くときには(そしてそれを使いまわしだしたりすると)恐ろしく煩雑に感じることと思います.
そこで,上のように書けるために以下のようなtype generator(ある型を(template引数として)取って,ある型を返すようなヘルパクラス)を定義してみます(後で言いますが,これはマズイ実装です).

template
struct enable_if_convertible{
  typedef typename 
    boost::enable_if >::type
    type;
};

これで問題にしていたコンストラクタテンプレートは以下のように若干短く書けます.

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

これは実際,SFINAEの条件として普通に働きます.
ところが,これをやると先ほどのis_convertibleがうまく働かなくなります.

std::cout << is_convertible, C >::value << std::endl; // コンパイルエラー!!

trueかfalseか以前にコンパイルエラーを引き起こしてしまいます.
問題はOtherTからTへ変換可能であるかどうかに関わらずenable_if_convertibleの依存型であるtypeが宣言されてしまっていることにあります.従って,OtherTがTに変換可能でない場合でも,enable_if_convertible::typeという型が宣言されているために,SFINAEの"Failure"が起きません.従って,コンパイラはis_convertible, C >を見た時点で,このコンストラクタを実体化しようとしますが,boost::enable_if >::typeが定義されていないために結果的にstruct enable_if_convertibleの内部でコンパイルエラーを引き起こす結果になります.
さて,困りましたね・・・ということで後編に続きます.