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
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.