8

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

6
  • Interesting, I just get one error, latest VC,c++17. invalid template argument for 'std::integer_sequence', expected compile-time constant expression in the to_sequence lambda. And that makes sense to me. Commented Oct 13, 2020 at 22:31
  • @lakeweb to me it does not because array is constexpr, and is are constexpr convertible to std::size_t. Maybe using decltype(is)::value? However gcc7.5 does not compile too... It is interesting ahaha Commented Oct 13, 2020 at 22:44
  • If I comment std::apply down, it does compile as constant, as it is no longer being used as a callable object. That makes sense to me. But I'm no expert where it comes to compile time programing. Commented Oct 13, 2020 at 23:09
  • 1
    Wouldn't it be easier to have it originally as an index sequence type, and then make a constexpr array out of that? Commented Oct 14, 2020 at 0:07
  • 1
    @Anonymous1847: It's not the answer to this question per the tags, but std::array<T> can be a template parameter (for suitable T) in C++20. Commented Oct 14, 2020 at 5:23

2 Answers 2

6

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Const references as template parameters? That's new to me. Interesting.
1

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;

1 Comment

It may be useful to explain your solution, instead of only providing a corrected code sample.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.