戻り値で SFINAE
#include <boost/utility/enable_if.hpp> #include <boost/type_traits/is_integral.hpp> template<typename T> void func(T, typename boost::enable_if<boost::is_integral<T> >::type* = 0 ){} // 戻り値型は、enable_if の第二引数 template<typename T> typename boost::enable_if<boost::is_integral<T>, void>::type func2(T){} struct hoge{ int value; }; // operator + は、引数が2つしか渡せないので戻り値型で判断する template<typename T> typename boost::enable_if<boost::is_integral<T>, hoge>::type operator +(hoge& lhs, T rhs){ hoge result; result.value = lhs.value + rhs; return result; } int main(){ func(10); // ok // func(0.0f); // error func('a'); // ok func2(10); // ok // func2(0.0f); // error func2('a'); // ok hoge h; h + 10; // ok // h + 0.0f; // error h + 'a'; // ok return 0; }
template 関数で、T型を制限する場合、SFINAE を使うテクニックがありますが、その戻り値版です。
引数に enable_if を記述するコードはよく見かけるんですが、戻り値に enable_if を記述するコードは見たことがなかったので書いてみました。
operator + などの演算子のオーバーロードは、引数を2つしか渡すことが出来ないので、こういう書き方になるんじゃないでしょか。
個人的にこっちの方がスマートなんだけど何か使われない理由があるか…。
まぁ、複数の条件を付ける場合は、引数で定義したほうが楽そうですね。
[追記]
VC8.0 では、SFINAE が出来ないとコメントを頂いたので試してみたんですが、問題なくコンパイルできたでござる。
試しに VC9.0 も試してみたんですが、こっちも問題なくコンパイル出来ました。
VC7.1 は手元にないので試せない…。
テストコードは、以下のとおり。
template<typename T> typename boost::enable_if<boost::is_same<T, int>, int>::type func2(T rhs){ std::cout << typeid(rhs).name() << ":is int" << std::endl; return rhs; } template<typename T> typename boost::enable_if<boost::is_same<T, char>, char>::type func2(T rhs){ std::cout << typeid(rhs).name() << ":is char" << std::endl; return rhs; } template<typename T> typename boost::enable_if<boost::is_same<T, float>, float>::type func2(T rhs){ std::cout << typeid(rhs).name() << ":is float" << std::endl; return rhs; }
[boost]
ver 1.44.0
[参照]
http://d.hatena.ne.jp/faith_and_brave/20081110/1226308533
http://cpplover.blogspot.com/2010/03/decltypesfinae.html