The idea of implementation is as follows (although boost.Mp11 may only need a few lines).
Take extract_from_tuple<float, double>
, where tuple
is tuple<int, char, char, double, double, float>
as an example, for each type, we can first calculate its corresponding indices in the tuple
, which is 5
for float
and 3, 4
for double
, then extract elements base on the indices and construct a tuple
with same types, finally use tuple_cat
to concatenate them together
#include <array>
#include <tuple>
#include <utility>
template<typename T, class Tuple>
constexpr auto
extract_tuple_of(const Tuple& t) {
constexpr auto N = std::tuple_size_v<Tuple>;
constexpr auto indices = []<std::size_t... Is>
(std::index_sequence<Is...>) {
std::array<bool, N> find{
std::is_same_v<std::tuple_element_t<Is, Tuple>, T>...
};
std::array<std::size_t, find.size()> indices{};
std::size_t size{};
for (std::size_t i = 0, j = 0; j < find.size(); j++) {
size += find[j];
if (find[j])
indices[i++] = j;
}
return std::pair{indices, size};
}(std::make_index_sequence<N>{});
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return std::tuple(std::get<indices.first[Is]>(t)...);
}(std::make_index_sequence<indices.second>{});
};
template<typename... Ts_out, class Tuple>
constexpr auto
extract_from_tuple(const Tuple& t) {
return std::tuple_cat(extract_tuple_of<Ts_out>(t)...);
}
Demo
constexpr auto tuple = std::make_tuple(1, 2, 3, 'a', 'b', 'c', 1.2, 2.3, 4.5f);
constexpr auto extract1 = extract_from_tuple<float, double>(tuple);
constexpr auto extract2 = extract_from_tuple<int>(tuple);
constexpr auto extract3 = extract_from_tuple<long>(tuple);
static_assert(extract1 == std::tuple<float, double, double>{4.5f, 1.2, 2.3});
static_assert(extract2 == std::tuple<int, int, int>{1, 2, 3});
static_assert(extract3 == std::tuple<>{});
constexpr
context – Isomauto extract = tuple;
to make a copy ? – Nicodemusextract
should equal{1.2,2.3,4.5f}
after extracing alldouble
andfloat
s fromtuple
– Nicodemus