【问题标题】:Is it possible to turn a constexpr std::array into a std::integer_sequence?是否可以将 constexpr std::array 转换为 std::integer_sequence?
【发布时间】:2019-06-27 23:15:18
【问题描述】:

也就是说,给定一个 constexpr std::array<int,2>{1,2} 将其传递给某个函数或帮助类,该类会输出 std::integer_sequence<int, 1, 2> 类型?

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

【问题讨论】:

  • 我有一种预感,不,这是不可能的,因为constexpr 函数可能仍会在运行时被调用。但是,这可能通过 C++20 中的 consteval 函数实现
  • 你的array有链接吗?
  • @Davis - 没有。至少,我认为不是——它是由基于模板参数的 constexpr 函数自己创建的。
  • @BeeOnRope:决定链接的不是它是如何产生的,而是它的存储位置(在命名空间、类、函数、类类型对象中)。
  • @Davis - 是的,但我的意思是“确定我希望它具有链接”,但鉴于它不是全球性的,我认为这并不明显。跨度>

标签: c++ templates c++14


【解决方案1】:

您似乎可以在 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 类型为std::integer_sequence&lt;int, 7, 15, 28&gt;。我不确定是否可以删除 lambda 使用。

【讨论】:

    【解决方案2】:

    如果数组有外部链接,你可以这样做:

    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

    【讨论】:

    • 内部链接也可以正常工作(从 C++11 开始,在这里可能很重要)。 C++17 不需要。
    【解决方案3】:

    这是一个与 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>;
    

    Live demo

    【讨论】:

      猜你喜欢
      • 2012-05-23
      • 2018-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-25
      • 2021-10-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多