How to make a function that zips two tuples in C++11 (STL)?

前端 未结 2 776
再見小時候
再見小時候 2020-12-25 14:35

I recently ran across this puzzle, was finally able to struggle out a hacky answer (using index arrays), and wanted to share it (answer below). I am sure there are answe

2条回答
  •  抹茶落季
    2020-12-25 15:11

    It isn't extremely difficult to do this for an arbitrary amount of tuples.

    One way is to make a function that collects all elements at a specific index from N tuples into a new tuple. Then have another function which collects those tuples into a new tuple for each index in the original tuples.

    All of that can be done relatively simply by expanding expressions with parameter packs, without any recursive functions.

    #include 
    #include 
    
    namespace detail {
        // Describe the type of a tuple with element I from each input tuple.
        // Needed to preserve the exact types from the input tuples.
        template
        using zip_tuple_at_index_t = std::tuple>...>;
    
        // Collect all elements at index I from all input tuples as a new tuple.
        template
        zip_tuple_at_index_t zip_tuple_at_index(Tuples && ...tuples) {
            return {std::get(std::forward(tuples))...};
        }
    
        // Create a tuple with the result of zip_tuple_at_index for each index.
        // The explicit return type prevents flattening into a single tuple
        // when sizeof...(Tuples) == 1 or sizeof...(I) == 1 .
        template
        std::tuple...> tuple_zip_impl(Tuples && ...tuples, std::index_sequence) {
            return {zip_tuple_at_index(std::forward(tuples)...)...};
        }
    
    }
    
    // Zip a number of tuples together into a tuple of tuples.
    // Take the first tuple separately so we can easily get its size.
    template
    auto tuple_zip(Head && head, Tail && ...tail) {
        constexpr std::size_t size = std::tuple_size_v>;
    
        static_assert(
            ((std::tuple_size_v> == size) && ...),
            "Tuple size mismatch, can not zip."
        );
    
        return detail::tuple_zip_impl(
            std::forward(head),
            std::forward(tail)...,
            std::make_index_sequence()
        );
    }
    

    See it in action here: https://wandbox.org/permlink/EQhvLPyRfDrtjDMw

    I used some C++14/17 features, but nothing essential. The most difficult part to replace would be the fold expression for checking the tuple sizes. That would probably have to become a recursive check.

提交回复
热议问题