Можно ли превратить constexpr std :: array в std :: integer_sequence? - PullRequest
12 голосов
/ 28 июня 2019

То есть, если constexpr std::array<int,2>{1,2} передать его некоторой функции или вспомогательному классу, который бы выплевывал тип std::integer_sequence<int, 1, 2>?

Кажется, легко перейти из мира типов в "значение constexpr"мир (например, чтобы сделать обратное преобразование), но трудно или невозможно сделать обратное.

Ответы [ 3 ]

9 голосов
/ 28 июня 2019

Похоже, что вы можете сделать это в C ++ 17, за счет введения лямбды на сайте вызовов:

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{});
};

Звонок make_seq вот так:

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

В результате получается x с типом std::integer_sequence<int, 7, 15, 28>. Я не уверен, можно ли убрать использование лямбды.

4 голосов
/ 28 июня 2019

Если массив имеет внешнюю связь, вы можете сделать что-то вроде:

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, "!");
}

Демо

Или, со структурой, вы можете сделать:

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]...>;
};

Демо

2 голосов
/ 28 июня 2019

Вот решение, совместимое с C ++ 14.

Уловка, чтобы "передать" constexpr std::array (или любой другой объект структуры / класса) в качестве аргумента шаблона, заключается в том, чтобы заключить его в тип:

constexpr std::array<int,3> a{7,15,28};
struct ArrayWrapper_a {
    static constexpr auto& value = a;
};

template<typename ArrayWrapper>
struct Foobar {
    // do stuff with ArrayWrapper::value
}

Затем вы можете сделать что-то похожее на ответ BeeOnRope, чтобы сгенерировать последовательности:

template<typename ArrayWrapper, typename Sequence>
struct array_to_sequence_impl;

template<typename ArrayWrapper, std::size_t... indices>
struct array_to_sequence_impl<ArrayWrapper,std::index_sequence<indices...>> {
    using value_type = typename std::decay_t<decltype(ArrayWrapper::value)>::value_type;
    using type = std::integer_sequence<value_type, std::get<indices>(ArrayWrapper::value)...>;
};

template<typename ArrayWrapper>
using array_to_sequence = typename array_to_sequence_impl<ArrayWrapper,std::make_index_sequence<ArrayWrapper::value.size()>>::type;

Использование:

constexpr std::array<int,3> a{7,15,28};
struct ArrayWrapper_a {
    static constexpr auto& value = a;
};
using Sequence_a = array_to_sequence<ArrayWrapper_a>;

Живая демоверсия

...