How to group data in tuples of tuples into a tuple of vectors

I want to group data of tuples in tuples into a tuple of vectors.
Given is a tuple of tuples containing data. There are multiple duplicate types, that’s data should be grouped into a vector of each unique type.

So far boost::mp11 is the most elegant way I found, to build a type
std::tuple<std::vector<T1>, std::tuple<std::vector<T2>, ...>
based on an incoming parameter pack
std::tuple<std::tuple<some_data>, std::tuple<std::tuple<some_more_data>, ...
using mp_unique and mp_transform to get vectors for each unique type.

Happy if you know a std::ish alternative (optional).

I am stuck finding a way to fill tuple elements into matching vectors?
I’d be excited, finding a fold expression’ish way to do so.

This example should help to give a better idea of what I have in mind.

template <typename T> using vector_of = std::vector<T>;

static constexpr auto tuple_to_vector(auto&&... Vs) noexcept {
    // merged_tuple = std::tuple<int, double, int, char, int, float, char, float, double>
    auto merged_tuple = std::tuple_cat(std::forward<decltype(Vs)>(Vs)...);
  
    // vector_t = std::tuple<std::vector<int>, std::vector<double>, std::vector<char>, std::vector<float>>
    using vector_t = boost::mp11::mp_transform<vector_of, boost::mp11::mp_unique<decltype(merged_tuple)>>; 
    vector_t vec;

    // how to add merged_tuple elements to vec
    // resulting in
    // std::tuple< std::vector<int>{1,3,2}, std::vector<double>{2.0,3.0}, std::vector<char>{'b','c'}, std::vector<float>{3.0f,2.0f}>
  
    return std::move(vec);
    
};

int main() {
    constexpr auto vec = tuple_to_vector(
        std::make_tuple(1,2.0,3),
        std::make_tuple('b',2,3.0f),
        std::make_tuple('c',2.0f,3.0)
    );
    // expecting
    // vec = std::tuple<
    //  std::vector<int>{1,3,2},
    //  std::vector<double>{2.0,3.0},
    //  std::vector<char>{'b','c'},
    //  std::vector<float>{3.0f,2.0f}
    // >
    return 42;
}

>Solution :

You can use std::apply to expand the elements of merged_tuple, and use std::get to extract the corresponding vector in vector_t according to the type of the element, and fill into the vector through push_back

std::apply([&vec](auto... args) {
   (std::get<std::vector<decltype(args)>>(vec).push_back(args), ...);
}, merged_tuple);

Demo

Note that vec cannot be constexpr even in C++20 since its allocation is non-transient.

Leave a Reply