zip

こんなのを思いついた。

template<class Pair>
struct zip;

template<class... S1, class... S2>
struct zip<pair<tuple<S1...>, tuple<S2...>>>
{
    typedef tuple<pair<S1, S2>...> type;
};

……けど S1 と S2 の長さが違うとアウトでしたorz


なので take を実装して長さを短いほうに合わせてからやってやるといけそうな感じ。


追記:
でけた!

// take
// リストの先頭部分を取り出す
// num→[α]→[α]
namespace take_detail
{
    template<class Num>
    struct env;

    template<int N>
    struct env<int_<N>>
    {
        template<class L, class A>
        struct f;

        template<class... S, class A>
        struct f<tuple<S...>, A>
        {
            typedef typename if_<bool_<(sizeof...(S) < N)>, typename binary_concat<tuple<S...>, tuple<A>>::type, tuple<S...>>::type type;
        };
    };
}

template<class Num, class L>
struct take
{
    typedef typename foldl<take_detail::env<Num>::template f, tuple<>, L>::type type;
};

// zip
// リストの対から対応する要素を取り出して対のリストを作る
// ([α], [β])→[(α, β)]
namespace zip_detail
{
    template<class L1, class L2>
    struct zip;

    template<class... S1, class... S2>
    struct zip<tuple<S1...>, tuple<S2...>>
    {
        typedef tuple<pair<S1, S2>...> type;
    };
}

template<class Pair>
struct zip;

template<class... S1, class... S2>
struct zip<pair<tuple<S1...>, tuple<S2...>>>
{
    typedef int_<(sizeof...(S1) < sizeof...(S2) ? sizeof...(S1) : sizeof...(S2))> min;
    typedef typename zip_detail::zip<typename take<min, tuple<S1...>>::type, typename take<min, tuple<S2...>>::type>::type type;
};
int main()
{
    typedef zip<pair<tuple<_1i, _2i>, tuple<_3i, _2i, _1i> > >::type zip_result;
    static_assert(is_same<zip_result, tuple<pair<_1i, _3i>, pair<_2i, _2i>>>::value, "failed");
}