読者です 読者をやめる 読者になる 読者になる

boost::fusion::vectorからstd::tupleへの変換

C++

GCC 4.4 + Boost 1.40.0だと以下のコードはコンパイルが通りません。

#include <tuple>
#include <boost/fusion/include/vector.hpp>

template <class Args>
struct hoge;

template <class... Args>
struct hoge<boost::fusion::vector<Args...>> { // エラー!
    typedef std::tuple<Args...> type;
};

int main() {}

これがエラーになるのは、GCC 4.4時点での可変引数テンプレートの実装では
固定長テンプレートパラメータを可変長テンプレートの部分特殊化として使用できないからだそうです。
(fusion::vectorはtemplate のようなテンプレートパラメータになってるので固定長)


# これがコンパイル通ったとしても、fusion::vectorの後ろはfusion::void_で埋められてるのでフィルタをかけないといけません



仕方がないので、fusion::vectorを再帰で回してstd::tupleに変換するメタ関数を書いてみました。
(boost::tupleだと固定長テンプレートパラメータとなり、扱いにくいのでstd::tupleにしてます)

#include <tuple>
#include <boost/type_traits.hpp>
#include <boost/mpl/int.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/value_at.hpp>
#include <boost/fusion/include/size.hpp>
#include <boost/fusion/include/pop_front.hpp>

template <class List, class FVector, int N>
struct fuvector_to_tuple_impl;

template <class... Args, class FVector, int N>
struct fuvector_to_tuple_impl<std::tuple<Args...>, FVector, N> {
    typedef typename fuvector_to_tuple_impl<
            std::tuple<Args...,
                       typename boost::fusion::result_of::value_at<FVector, boost::mpl::int_<0>>::type>,
            typename boost::fusion::result_of::pop_front<FVector>::type,
            N - 1
        >::type
    type;
};

template <class... Args, class FVector>
struct fuvector_to_tuple_impl<std::tuple<Args...>, FVector, 0> {
    typedef std::tuple<Args...> type;
};


template <class FVector>
struct fuvector_to_tuple {
    typedef typename fuvector_to_tuple_impl<
            std::tuple<>,
            FVector,
            boost::fusion::result_of::size<FVector>::value
        >::type
    type;
};

int main()
{
    typedef boost::fusion::vector<int, char, double> types;
    static_assert(boost::is_same<fuvector_to_tuple<types>::type,
                                 std::tuple<int, char, double> >::value, "not same");
}