テンプレートテンプレートパラメータに Boost.MPL のラムダ式を渡す
以下のようにテンプレートテンプレートパラメータを受け取るテンプレートクラスがあるとします。
template< typename T, typename U, template<typename, typename> class Pred = boost::is_same > struct equal{ typedef Pred<T, U> type; }; // OK BOOST_MPL_ASSERT(( equal<int, int> )); // OK BOOST_MPL_ASSERT(( equal<mpl::int_<11>, mpl::long_<11>, mpl::equal_to> ));
上記のクラスでは、型の比較を行うためのテンプレートクラスを引数に受け取って処理を行っています。
しかし、上記のようにテンプレートテンプレートパラメータで受け取ると、テンプレート引数が2つのクラスしか受け取る事が出来ないので、次のような書き方は出来ません。
// NG BOOST_MPL_ASSERT(( equal< mpl::vector<int, char, float>, mpl::vector<int, char, float>, mpl::equal // mpl::equal はテンプレートパラメータが3つあるので渡せない >::type ));
これは、mpl::equal が、3つのテンプレート引数で定義されている為、template
// mpl::equal template< typename Seq1, typename Seq2, typename Pred = is_same<_1, _2> > struct equal;
と、いうことで、こういう場合に対応させるためのラッパーを簡単に書いてみました。
[ソース]
#include <boost/mpl/assert.hpp> #include <boost/mpl/apply.hpp> #include <boost/mpl/vector.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/long.hpp> #include <boost/mpl/equal_to.hpp> #include <boost/type_traits/is_same.hpp> namespace mpl = boost::mpl; // Boost.MPL の Lambda Expression の評価を行う為のラッパー template<typename Expr> struct applicable{ // テンプレートテンプレートパラメータによって渡す template<typename T0> struct apply1 : mpl::apply1<Expr, T0>{}; template<typename T0, typename T1> struct apply2 : mpl::apply2<Expr, T0, T1>{}; }; template< typename T, typename U, template<typename, typename> class Pred = boost::is_same > struct equal{ typedef Pred<T, U> type; }; BOOST_MPL_ASSERT(( equal<int, int> )); BOOST_MPL_ASSERT(( equal<mpl::int_<11>, mpl::long_<11>, mpl::equal_to> )); BOOST_MPL_ASSERT(( equal<int, char, applicable<boost::is_same<mpl::_1, int> >::apply2>::type )); // OK BOOST_MPL_ASSERT(( equal< mpl::vector<int, char, float>, mpl::vector<int, char, float>, applicable<mpl::equal<mpl::_1, mpl::_2, mpl::quote2<boost::is_same> > >::apply2 // テンプレートテンプレートパラメータに合わせる >::type )); int main(){ return 0; }
こんな感じで、テンプレートテンプレートパラメータに渡すことが出来るように Boost.MPL のラムダ式をラップして評価しています。
仕組み自体はそんなに難しくないかな。
ところで、Boost.MPL で似たようなことって出来ませんかね。
[おまけ1]
件の問題が、テンプレートテンプレートパラメータの数だけであれば、Variadic Templates を使用すれば解決します。
template< typename T, typename U, template<typename...> class Pred = boost::is_same > struct equal{ typedef Pred<T, U> type; }; // OK BOOST_MPL_ASSERT(( equal< mpl::vector<int, char, float>, mpl::vector<int, char, float>, mpl::equal > ));
[おまけ2]
そもそもテンプレートテンプレートパラメータを使用するのではなくて、Boost.MPL の apply で評価したほうがいいんじゃないかなーと思いますね。
mpl::equal も同じように処理していますし。
template< typename T, typename U, // Lambda Expression を引数に受け取る typename Pred = boost::is_same<mpl::_1, mpl::_2> > struct equal{ // mpl::apply で評価 typedef typename mpl::apply2<Pred, T, U>::type type; }; // OK BOOST_MPL_ASSERT(( equal< mpl::int_<11>, mpl::long_<11>, mpl::equal_to<mpl::_1, mpl::_2> > )); // OK BOOST_MPL_ASSERT(( equal< mpl::vector<int, char, float>, mpl::vector<int, char, float>, mpl::equal<mpl::_1, mpl::_2, mpl::quote2<boost::is_same> > >::type ));