type_traits(メタ関数)とSFINAE

さて,以上でCからCへ暗黙に変換できるようになったわけですが,実は一つ問題が残っています.問題は以下のコードを実行すると分かります.

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

boost::is_convertibleはBoost.TypeTraitsライブラリにあるメタ関数で,型から型への暗黙の変換が可能かどうかを知ることができます.
で,問題は上のコードが"1"を表示する,要するにis_convertibleがtrueを返すことです.ですが,さっき書いたとおりCからCへの暗黙の型変換は不可能です.なのに,なぜこれがtrueを返すかというと,コンストラクタtemplateの宣言だけ見るとCからCへの暗黙の型変換があるように見えるからです.

template
C(C const &r);

これだけ見るとあらゆるCからの型変換が可能に見えます.で,実際boost::is_convertibleはこれからCからCへの暗黙の型変換が可能であると判断してtrueを返します.もちろん他のあらゆる変換CからCなどの変換なども可能であると誤判定してしまいます.
ちなみにこの問題はK.INABA氏の本で指摘されているのを読んで初めて気がついたものです.
(´-`).。oO(っていうか本当に良い本だ・・・)
さて,この問題を避けるためにはある型T1が別の型T2に暗黙に変換できるときだけCを引数にとるCのコンストラクタを定義する,という非常に高度なことをやらなければなりません.これを実現するためにSFINAEを利用します.
class Cのコンストラクタテンプレートは以下のように書き直せます.

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

ダミーの第2引数によって,このコンストラクタはOtherTがTに変換可能であるときにしか宣言されません.たとえば,OtherTがchar*でTがintであるようなコンストラクタは宣言されないことになります.従って,上のようなコンストラクタテンプレートの定義であれば,is_convertible, C >は正しく動作してfalseを返してくれます.