Boost.MPL に対応させた Variadic Templates のラッパを書いた
以前、Variadic Templates のパラメータを mpl::vector に変換する処理を書いたんですが、今回は、直接 Boost.MPL に拡張する形で書いてみました。
満たしているコンセプトは、
- Forward Sequence
- Front Extensible Sequence
- Back Extensible Sequence
- Forward Iterator
です。
これらのコンセプトを要求している Boost.MPL のメタ関数を他の Sequence と同じように扱うことが出来ます。多分。
[ソース]
#include <boost/mpl/equal_to.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/size.hpp> #include <boost/mpl/empty.hpp> #include <boost/mpl/size_t.hpp> #include <boost/mpl/front.hpp> #include <boost/mpl/back.hpp> #include <boost/mpl/identity.hpp> #include <boost/mpl/next.hpp> #include <boost/mpl/deref.hpp> #include <boost/mpl/pop_back.hpp> #include <boost/mpl/push_back.hpp> #include <boost/mpl/pop_front.hpp> #include <boost/mpl/push_front.hpp> #include <boost/mpl/copy.hpp> #include <boost/mpl/clear.hpp> #include <boost/mpl/prior.hpp> #include <boost/mpl/iterator_tags.hpp> struct variadic_tag; template<typename ...Args> struct variadic{ typedef variadic_tag tag; typedef variadic<Args...> type; }; template<typename ...Args> struct variadic_iterator; template<typename Head, typename ...Tail> struct variadic_iterator<Head, Tail...>{ typedef Head type; typedef variadic_iterator<Tail...> next; typedef boost::mpl::forward_iterator_tag category; }; template<> struct variadic_iterator<>{ typedef boost::mpl::forward_iterator_tag category; }; /** Variadic Templates 用のメタ関数 */ template<typename ...Args> struct empty : boost::mpl::false_{}; template<> struct empty<> : boost::mpl::true_{}; template<typename ...Args> struct size : boost::mpl::size_t<sizeof...(Args)>{}; template<typename Seq, typename T> struct push_back; template<typename ...Args, typename T> struct push_back<variadic<Args...>, T>{ typedef variadic<Args..., T> type; }; template<typename ...Args> struct pop_back; template<typename T1, typename T2, typename T3, typename ...Args> struct pop_back<T1, T2, T3, Args...>{ template<typename Seq, typename T> struct merge; template<typename ...ArgsT, typename T> struct merge<variadic<ArgsT...>, T>{ typedef variadic<ArgsT..., T> type; }; template<typename ...Args1, typename ...Args2> struct merge<variadic<Args1...>, variadic<Args2...> >{ typedef variadic<Args1..., Args2...> type; }; typedef typename merge< variadic<T1, T2>, typename pop_back<T3, Args...>::type >::type type; }; template<typename T, typename U> struct pop_back<T, U>{ typedef variadic<T> type; }; template<typename T> struct pop_back<T>{ typedef variadic<> type; }; template<typename ...Args> struct back; template<typename T, typename ...Args> struct back<T, Args...>{ typedef typename back<Args...>::type type; }; template<typename T> struct back<T>{ typedef T type; }; template<typename ...Args> struct pop_front; template<typename T, typename ...Args> struct pop_front<T, Args...>{ typedef variadic<Args...> type; }; template<typename Seq, typename T> struct push_front; template<typename ...Args, typename T> struct push_front<variadic<Args...>, T>{ typedef variadic<T, Args...> type; }; template<typename ...Args> struct front; template<typename T, typename ...Args> struct front<T, Args...> : boost::mpl::identity<T>{}; /** Boost.MPL へのアダプト */ namespace boost{ namespace mpl{ template<> struct size_impl<variadic_tag>{ template<typename Seq> struct apply; template<typename ...Args> struct apply<variadic<Args...> > : ::size<Args...>{}; }; template<> struct empty_impl<variadic_tag>{ template<typename Seq> struct apply; template<typename ...Args> struct apply<variadic<Args...> > : ::empty<Args...>{}; }; template<> struct begin_impl<variadic_tag>{ template<typename Seq> struct apply; template<typename ...Args> struct apply<variadic<Args...> > : identity<variadic_iterator<Args...> >{}; }; template<> struct end_impl<variadic_tag>{ template<typename T> struct apply; template<typename ...Args> struct apply<variadic<Args...> > : identity<variadic_iterator<> >{}; }; template<typename ...Args> struct next< variadic_iterator<Args...> >{ typedef typename variadic_iterator<Args...>::next type; }; template<> struct back_impl<variadic_tag>{ template<typename Seq> struct apply; template<typename ...Args> struct apply<variadic<Args...> > : ::back<Args...>{}; }; template<> struct push_back_impl<variadic_tag>{ template<typename Seq, typename T> struct apply : ::push_back<Seq, T>{}; }; template<> struct pop_back_impl<variadic_tag>{ template<typename Seq> struct apply; template<typename ...Args> struct apply<variadic<Args...> > : ::pop_back<Args...>{}; }; template<> struct front_impl<variadic_tag>{ template<typename Seq> struct apply; template<typename ...Args> struct apply<variadic<Args...> > : ::front<Args...>{}; }; template<> struct push_front_impl<variadic_tag>{ template<typename Seq, typename T> struct apply : ::push_front<Seq, T>{}; }; template<> struct pop_front_impl<variadic_tag>{ template<typename Seq> struct apply; template<typename ...Args> struct apply<variadic<Args...> > : ::pop_front<Args...>{}; }; template<> struct clear_impl<variadic_tag>{ template<typename Seq> struct apply; template<typename ...Args> struct apply<variadic<Args...> > : identity<variadic<> >{}; }; } } // namespace boost{ namespace mpl{ /** 適当なテスト */ #include <boost/mpl/assert.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/mpl/vector.hpp> #include <boost/mpl/print.hpp> #include <boost/mpl/at.hpp> #include <boost/mpl/count.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/transform.hpp> #include <boost/mpl/inserter.hpp> #include <boost/type_traits/add_pointer.hpp> #include <boost/mpl/fold.hpp> namespace mpl = boost::mpl; typedef variadic<int, float, void, char, double> sequence; BOOST_MPL_ASSERT(( mpl::equal_to< mpl::size<sequence>, mpl::int_<5> > )); BOOST_MPL_ASSERT(( mpl::equal< mpl::pop_back<sequence>::type, variadic<int, float, void, char> > )); BOOST_MPL_ASSERT(( mpl::equal< mpl::pop_front<sequence>::type, variadic<float, void, char, double> > )); BOOST_MPL_ASSERT(( mpl::equal< mpl::copy<variadic<short, long> , mpl::back_inserter<sequence> >::type, variadic<int, float, void, char, double, short, long> > )); BOOST_MPL_ASSERT(( mpl::equal< mpl::transform<sequence, boost::add_pointer<mpl::_1> >::type, variadic<int*, float*, void*, char*, double*> > )); /** Boost.MPL Sequence → std::tuple のアダプタ */ #include <tuple> template<typename T, typename U> struct variadic_copy; template< template <typename ...> class Seq, template <typename ...> class Result, typename ...TArgs, typename ...UArgs > struct variadic_copy<Seq<TArgs...>, Result<UArgs...> >{ typedef Result<TArgs...> type; }; template<typename Seq> struct to_tuple : variadic_copy< typename mpl::copy< Seq, mpl::back_inserter<variadic<> > >::type, std::tuple<> > {}; BOOST_MPL_ASSERT(( boost::is_same< to_tuple<mpl::vector<int, float, double> >::type, std::tuple<int, float, double> > )); #include <iostream> int main(){ to_tuple<mpl::vector<int, float, double> >::type t(42, 3.14f, 0.5); int n; float f; double d; std::tie(n, f, d) = t; std::cout << n << " " << f << " " << d << std::endl; return 0; }
[出力]
42 3.14 0.5
end の処理がよく分からんので iterator で適当に void_ を返しています。
うーむむ。
あと Template Parameter を他のクラスに渡すのがちょっとめんどくさいですね…。(variadic_copy の辺り。
もっとスマートな方法とかあるんでしょうか。
pop_back 等も Template Parameter を返す方法が分からなかったので、variadic でラップして返しています(´・ω・`)
[boost]
- ver 1.47.0
[追記]
コメント頂いたのでそれに合わせて修正。