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

[追記]

コメント頂いたのでそれに合わせて修正。