Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to turn a constexpr std::array into a std::integer_sequence?

That is, given a constexpr std::array<int,2>{1,2} pass it to some function or helper class that would spit out the type std::integer_sequence<int, 1, 2>?

It seems easy to jump from the type world to the "constexpr value" world (e.g., to do the reverse conversion), but hard or impossible to do the reverse.

like image 846
BeeOnRope Avatar asked Jun 27 '19 23:06

BeeOnRope


2 Answers

It seems like you can do it in C++17, at the cost of introducing a lambda at the call site:

template <size_t N, typename F, size_t... indexes>
constexpr auto make_seq_helper(F f, std::index_sequence<indexes...> is) {
    return std::integer_sequence<int, std::get<indexes>(f())...>{};
}

template <typename F>
constexpr auto make_seq(F f) {
    constexpr size_t N = f().size();
    using indexes = std::make_index_sequence<N>;
    return make_seq_helper<N>(f, indexes{});
};

Calling make_seq like this:

    constexpr std::array a{7, 15, 28};
    auto x = make_seq([](){ return a; });

Results in an x with type std::integer_sequence<int, 7, 15, 28>. I'm not sure if the lambda use can be removed.

like image 173
BeeOnRope Avatar answered Oct 04 '22 05:10

BeeOnRope


If array have external linkage, you might do something like:

template <auto& Arr, size_t... Is>
constexpr auto make_seq_impl(std::index_sequence<Is...>) {
    using T = typename std::decay_t<decltype(Arr)>::value_type;
    return std::integer_sequence<T, Arr[Is]...>{};
}

template <auto& Arr>
constexpr auto make_seq() {
    return make_seq_impl<Arr>(std::make_index_sequence<Arr.size()>());
}

constexpr std::array a{7, 15, 28};

int main()
{
    [[maybe_unused]]auto x = make_seq<a>();
    static_assert(std::is_same<std::integer_sequence<int, 7, 15, 28>, decltype(x)>::value, "!");
}

Demo

Or, with structure way, you might do:

template <const auto& Arr, typename Seq = std::make_index_sequence<std::size(Arr)>>
struct make_seq;

template <typename T, std::size_t N, const std::array<T, N>& Arr, std::size_t ... Is>
struct make_seq<Arr, std::index_sequence<Is...>>
{
    using type = std::integer_sequence<T, Arr[Is]...>;
};

Demo

like image 27
Jarod42 Avatar answered Oct 04 '22 05:10

Jarod42