是否可以将constexpr std :: array转换为std :: integer_sequence?

时间:2019-06-27 23:15:18

标签: c++ templates c++14

也就是说,给定constexpr std::array<int,2>{1,2}并将其传递给某些吐出类型std::integer_sequence<int, 1, 2>的函数或辅助类吗?

从类型世界跳到“ constexpr值”世界似乎很容易(例如,进行反向转换),但是很难或不可能进行反向。

3 个答案:

答案 0 :(得分:9)

您似乎可以在C ++ 17中做到这一点,但要在调用站点引入lambda:

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的{​​{1}}。我不确定是否可以删除lambda用法。

答案 1 :(得分:4)

如果数组具有外部链接,则可以执行以下操作:

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

或者,通过结构方式,您可以这样做:

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

答案 2 :(得分:2)

这是C ++ 14兼容的解决方案。

constexpr std::array(或任何其他struct / class对象)作为模板参数“传递”的技巧是将其包装为类型:

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>;

Live demo