Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transforming an array of int to integer_sequence

Tags:

c++

c++17

I would like to know if there is a way to transform a std::array into an index sequence?

constexpr std::array<int, 5> x = {0, 3, 4, 5, 8};

constexpr auto integer_sequence = ...; // something that lead to integer_sequence<int, 0, 3, 4, 5, 8>;

I know that it is impossible to use a function, because it will lead to another type. However, since it is possible to do something like :

constexpr std::size_t x = 8;
std::integral_constant<int, x> height;

Is it possible to do it in a simple way?

I tried to do the following :

#include <array>
#include <tuple>

template<std::size_t N>
constexpr std::array<int, N> m_iota(int value) {
    std::array<int, N> result{};
    for(auto &v : result)
        v = value++;
    return result;
}

template<int N>
using Int = std::integral_constant<int, N>;

int main() {
    constexpr auto array = m_iota<5>(3); // 3, 4, 5, 6, 7
    constexpr auto indexer = std::tuple<Int<0>,Int<1>,Int<2>,Int<3>,Int<4>>{};

    auto to_sequence = [array](auto ...is) {return std::integer_sequence<int, array[is]...>{};};
    auto x = std::apply(to_sequence, indexer);
    static_assert(std::is_same_v<decltype(x), std::integer_sequence<int, 3, 4, 5, 6, 7>>);
}

It compiles well on GCC and clang, but not in MSVC... Is there simpler way?

Here a link to msvc : https://godbolt.org/z/EK7azW

like image 400
Antoine Morrier Avatar asked Oct 13 '20 22:10

Antoine Morrier


2 Answers

While (in C++17) std::array<T> can't be a template parameter type, const std::array<T>& can be. Thus, with the restriction that the array in question have static storage duration, you can write

#include<array>
#include<utility>
#include<type_traits>
#include<cstddef>

template<const auto &A,
         class=std::make_index_sequence<
           std::tuple_size<std::decay_t<decltype(A)>>::value>>
struct as_sequence;
template<const auto &A,std::size_t ...II>
struct as_sequence<A,std::index_sequence<II...>> {
    using type=std::integer_sequence<
      typename std::decay_t<decltype(A)>::value_type,A[II]...>;
};

constexpr std::array<int, 5> x = {0, 3, 4, 5, 8};
static_assert(std::is_same_v<as_sequence<x>::type,
                std::integer_sequence<int, 0, 3, 4, 5, 8>>);

which works on every modern compiler.

like image 184
Davis Herring Avatar answered Nov 20 '22 08:11

Davis Herring


You can try this:

constexpr std::array<int, 5> x = {0, 3, 4, 5, 8};

template <int prepender, typename sequence>
struct prepend_integer_to_sequence {};

template <int prepender, int... sequence_nums>
struct prepend_integer_to_sequence<prepender, std::integer_sequence<int, sequence_nums...> > {
    using type = std::integer_sequence<int, prepender, sequence_nums...>;
};
    
template <int prepender, typename sequence>
using prepend_integer_to_sequence_t = typename prepend_integer_to_sequence<prepender, sequence>::type;


template <size_t begin>
struct convert_array {
    using type = prepend_integer_to_sequence_t<
        x[begin],
        typename convert_array<begin + 1>::type
    >;
};

template <>
struct convert_array<x.size()> {
    using type = std::integer_sequence<int>;
};

using int_seq = typename convert_array<0>::type;
like image 44
Anonymous1847 Avatar answered Nov 20 '22 10:11

Anonymous1847