Construct an array of indices of std::tuple types

Viewed 59

Given a tuple containing elements of distinct types (no two are the same):

typedef std::tuple<bool, char, int, float, double, std::string> t1;

and a tuple type containing elements restricted to those types (duplicates and omissions are possible, but no additional types):

typedef std::tuple<char, int, int, double, std::string, int, double> t2;

How can I construct a std::array containing the indices of the matching element in t1 for the elements in t2?

{1, 2, 2, 4, 5, 2, 4}
1 Answers

Sure, that's doable.
Let's give std::integer_sequence, std::tuple and related machinery a workout.

First, code a way to get the index of the single unique match for an arbitrary type in something tuple-like:

template <class T, class U, std::size_t... N>
static constexpr auto tuple_index_impl(std::index_sequence<N...>) noexcept {
    static_assert((std::size_t() + ... + std::is_same_v<T, std::tuple_element_t<N, U>>) == 1,
        "There is no single exact match");
    return (0 + ... + (N * std::is_same_v<T, std::tuple_element_t<N, U>>));
}
template <class T, class U>
static constexpr std::size_t
tuple_index_v = tuple_index_impl<T, U>(std::make_index_sequence<std::tuple_size_v<U>>());

A pity that's not part of the standard-library already.

Next, use that to get all the indices and put them into a std::array:

template <class T, class U, std::size_t... N>
constexpr auto indices_impl(std::index_sequence<N...>) noexcept {
    return std::array<std::size_t, sizeof...(N)>{tuple_index_v<std::tuple_element_t<N, U>, T>...};
}
template <class T, class U>
constexpr auto indices() noexcept {
    return indices_impl<T, U>(std::make_index_sequence<std::tuple_size_v<U>>());
}

An example-use:

for (auto x : indices<t1, t2>())
    std::cout << x << '\n';

See it live on coliru.

Related