複数条件での enable_if
元ネタ:ボレロ村上 - ENiyGmaA Code - enable_switch - 複数の重複しうるコンパイル時条件で、SFINAE によるオーバーロードを書くには
SFINAE を使用する上で、この機能は欲しかったので自分も書いてみました。
二番煎じ乙。
#include <boost/utility/enable_if.hpp> #include <boost/mpl/apply.hpp> #include <boost/mpl/and.hpp> #include <boost/mpl/at.hpp> #include <boost/mpl/transform.hpp> #include <boost/mpl/bool.hpp> #include <boost/mpl/equal_to.hpp> #include <boost/mpl/plus.hpp> #include <boost/mpl/count_if.hpp> namespace detail{ namespace mpl = boost::mpl; template<typename Seq, typename N, typename M> struct slice : mpl::iterator_range< typename mpl::advance<typename mpl::begin<Seq>::type, N>::type, typename mpl::advance<typename mpl::begin<Seq>::type, M>::type > {}; template<typename Seq, typename Pred> struct is_only_one_if : mpl::equal_to< mpl::count_if<Seq, Pred>, mpl::int_<1> > {}; using mpl::_1; template<typename Seq, typename T> struct apply : mpl::transform<Seq, mpl::apply1<_1, T> >{}; template<typename Seq, typename N, typename U> struct enables_if_c_impl : boost::enable_if< // seq[N] && (count(seq[0, N+1], true) == 1) mpl::and_< mpl::at<Seq, N>, is_only_one_if< slice< Seq, mpl::int_<0>, mpl::plus<N, mpl::int_<1> > >, mpl::equal_to<mpl::_1, mpl::true_> > >, U > {}; template<typename Seq, typename N, typename T, typename U> struct enables_if_impl : enables_if_c_impl<typename apply<Seq, T>::type, N, U>{}; } // namespace detail template<typename Seq, typename N, typename T, typename U = void> struct enables_if : detail::enables_if_impl<Seq, N, T, U>{}; template<typename Seq, typename N, typename U = void> struct enables_if_c : detail::enables_if_c_impl<Seq, N, U>{}; #include <boost/type_traits/is_integral.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/is_class.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/vector.hpp> #include <boost/mpl/always.hpp> #include <string> #include <iostream> namespace mpl = boost::mpl; using mpl::_1; typedef mpl::vector< boost::is_same<int, _1>, boost::is_integral<_1>, boost::is_class<_1>, mpl::always<mpl::true_> > enables; template<typename T> void test(T t, typename enables_if<enables, mpl::int_<0>, T>::type* =0){ std::cout << "int:" << t << std::endl; } template<typename T> void test(T t, typename enables_if<enables, mpl::int_<1>, T>::type* =0){ std::cout << "long:" << t << std::endl; } template<typename T> void test(T t, typename enables_if<enables, mpl::int_<2>, T>::type* =0){ std::cout << "class:" << t << std::endl; } template<typename T> void test(T t, typename enables_if<enables, mpl::int_<3>, T>::type* =0){ std::cout << "other:" << t << std::endl; } int main(){ test(0); test(long(100)); test(std::string("str")); test(0.0f); return 0; }
[出力]
int:0 long:100 class:str other:0
機能的には元ネタに劣るけど、とりあえず、これでいいかなーと。
Variadic Templates 使いたい……。
[boost]
var 1.46.1
[参照]
http://d.hatena.ne.jp/boleros/20110222/1298394129