我如何在``sTD :: integer_sepence< int,4,-5、7,-3>`中扭转整数的顺序?

发布于 2025-02-09 08:37:53 字数 1873 浏览 0 评论 0原文

有时我想在index_sequence中扭转值,并使用结果扭转 tuple类似 的值,就像在此插图中,它逆转了一个Constexpr std :: Array在编译时。

#include <array>
#include <cstdint>
#include <utility>

namespace detail {
template <class T, std::size_t N, std::size_t... I>
    constexpr std::array<T, N> rev_arr_helper(const std::array<T, N>& arr,
                                              std::index_sequence<I...>) {
        return {arr[sizeof...(I) - I - 1]...};

        //     {arr[4-0-1], arr[4-1-1], arr[4-2-1], arr[4-3-1]}
        //     =>
        //     {arr[3], arr[2], arr[1], arr[0]}
    }
}  // namespace detail

template <class T, std::size_t N>
constexpr std::array<T, N> rev_arr(const std::array<T, N>& arr) {
    return detail::rev_arr_helper(arr, std::make_index_sequence<N>{});
}

int main() {
    constexpr std::array<int, 4> arr{11, 22, 33, 44};
    constexpr auto rev = rev_arr(arr);    
    static_assert(rev[0] == 44 && rev[1] == 33 && rev[2] == 22 && rev[3] == 11, "");
}

现在,此方法不适用于任何 integer_sequence,就像标题中的一种一样。它仅适用于那些订购的0、1、2,...,N-1,我希望能够使用C ++ 14:

#include <type_traits>
#include <utility>

int main() {
    std::integer_sequence<int, 4, -5, 7, -3> iseq;
    std::integer_sequence<int, -3, 7, -5, 4> itarget;

    auto irev = reverse_sequence(iseq);

    static_assert(std::is_same<decltype(irev), decltype(itarget)>::value, "");
}

如何完成该编译?


这是从评论中收集的一个有点相关的Q&amp; 我如何逆转订单元素类型中的元素类型?

Sometimes I want to reverse the values in an index_sequence and use the result to reverse the values in something tuple-like, like in this illustration which reverses the values in a constexpr std::array at compile time.

#include <array>
#include <cstdint>
#include <utility>

namespace detail {
template <class T, std::size_t N, std::size_t... I>
    constexpr std::array<T, N> rev_arr_helper(const std::array<T, N>& arr,
                                              std::index_sequence<I...>) {
        return {arr[sizeof...(I) - I - 1]...};

        //     {arr[4-0-1], arr[4-1-1], arr[4-2-1], arr[4-3-1]}
        //     =>
        //     {arr[3], arr[2], arr[1], arr[0]}
    }
}  // namespace detail

template <class T, std::size_t N>
constexpr std::array<T, N> rev_arr(const std::array<T, N>& arr) {
    return detail::rev_arr_helper(arr, std::make_index_sequence<N>{});
}

int main() {
    constexpr std::array<int, 4> arr{11, 22, 33, 44};
    constexpr auto rev = rev_arr(arr);    
    static_assert(rev[0] == 44 && rev[1] == 33 && rev[2] == 22 && rev[3] == 11, "");
}

Now, this approach does not work for any integer_sequence, like the one in the title. It only works for those ordered 0, 1, 2, ..., N-1 and I would like to be able to make this compile using C++14:

#include <type_traits>
#include <utility>

int main() {
    std::integer_sequence<int, 4, -5, 7, -3> iseq;
    std::integer_sequence<int, -3, 7, -5, 4> itarget;

    auto irev = reverse_sequence(iseq);

    static_assert(std::is_same<decltype(irev), decltype(itarget)>::value, "");
}

How can that be done?


Here's a somewhat related Q&A collected from the comments:
How do I reverse the order of element types in a tuple type?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不爱素颜 2025-02-16 08:37:53

一种解决方案是创建一个std :: index_sequence,能够使用下标操作员模拟integer_secerence中的值。通过将整数的顺序放在i ...中在元组中的某个位置提取值。我们想要类似于i [pos] ...(是否奏效)的东西,这就是我们所获得的:

std::get<pos>( std::tuple<decltype(I)...>{I...} )...
  • sidenote:&lt; exptype(i)...&gt;需要以上以使其在C ++ 14中起作用。在C ++ 17及以后,可以简单地做:
      std :: get&lt; pos&gt;(std :: tuple {i ...})...
     

将其放置在适当的位置使其非常相似,就像倒在数组中的元素:

#include <cstddef>
#include <tuple>
#include <utility>

namespace detail {
template <class T, T... I, std::size_t... J>
constexpr auto rev_helper(std::integer_sequence<T, I...>, std::index_sequence<J...>)
{
return
std::integer_sequence<T,
std::get<sizeof...(J) - J - 1>(std::tuple<decltype(I)...>{I...})...>{};
//

One solution is to create a std::index_sequence to be able to simulate using the subscript operator to access the values in your integer_sequence. By putting the sequence of integers, I..., in a std::tuple one can use std::get<> to extract the value at a certain position in the tuple. We want something similar to I[pos]... (had it worked) which is what we get with:

std::get<pos>( std::tuple<decltype(I)...>{I...} )...
  • Sidenote: <decltype(I)...> above is needed to make it work in C++14. In C++17 and later, one can simply do:
    std::get<pos>( std::tuple{I...} )...
    

Putting that in place makes it very similar to reversing the elements in an array:

#include <cstddef>
#include <tuple>
#include <utility>

namespace detail {
    template <class T, T... I, std::size_t... J>
    constexpr auto rev_helper(std::integer_sequence<T, I...>, std::index_sequence<J...>)
    {
        return
            std::integer_sequence<T,
                std::get<sizeof...(J) - J - 1>(std::tuple<decltype(I)...>{I...})...>{};
//                       ????                  ????                            /    \
//       index_sequence: └─── 3, 2, 1, 0 ───┘       integer_sequence: 4, -5, 7, -3
    }
}  // namespace detail

This will with the example integer_sequence<int, 4, -5, 7, -3> then be expanded to the type:

std::integer_sequence<int,
    std::get<3>(std::tuple<int,int,int,int>{4, -5, 7, -3}), // -3
    std::get<2>(std::tuple<int,int,int,int>{4, -5, 7, -3}), //  7
    std::get<1>(std::tuple<int,int,int,int>{4, -5, 7, -3}), // -5
    std::get<0>(std::tuple<int,int,int,int>{4, -5, 7, -3})  //  4
>

which is the same as the target type std::integer_sequence<int, -3, 7, -5, 4>.

The front-end for the helper function just takes the original integer_sequence and passes it on to the helper with an index_sequence:

template <class T, T... I>
constexpr auto reverse_sequence(std::integer_sequence<T, I...> seq) {
    return detail::rev_helper(seq, std::make_index_sequence<sizeof...(I)>{});
}

Demo

烟酉 2025-02-16 08:37:53

不使用std :: tuple的解决方案是将std :: array转换为std :: make_index_sequence访问相应的索引

namespace detail {
    template<typename T, T... N, std::size_t... Indices>
    constexpr auto reverse_sequence_helper(std::integer_sequence<T, N...> sequence,
                                           std::index_sequence<Indices...>) {
        constexpr auto array = std::array<T, sizeof...(N)> { N... };
        return std::integer_sequence<T, array[sizeof...(Indices) - Indices - 1]...>();
    }
}
template<typename T, T... N>
constexpr auto reverse_sequence(std::integer_sequence<T, N...> sequence) {
    return detail::reverse_sequence_helper(sequence,
                                           std::make_index_sequence<sizeof...(N)>());
}

如果可用C ++ 20,则可以在模板的Lambdas的帮助下将其简化为此功能:

template<typename T, T... N>
constexpr auto reverse_sequence(std::integer_sequence<T, N...> sequence) {
    constexpr auto array = std::array { N... };
 
    auto make_sequence = [&]<typename I, I... Indices>(std::index_sequence<Indices...>) {
        return std::integer_sequence<T, array[sizeof...(Indices) - Indices - 1]...>();
    };
    return make_sequence(std::make_index_sequence<sizeof...(N)>());
}

A solution that doesn't use std::tuple is to convert to an std::array and access the corresponding indices with the help of std::make_index_sequence.

namespace detail {
    template<typename T, T... N, std::size_t... Indices>
    constexpr auto reverse_sequence_helper(std::integer_sequence<T, N...> sequence,
                                           std::index_sequence<Indices...>) {
        constexpr auto array = std::array<T, sizeof...(N)> { N... };
        return std::integer_sequence<T, array[sizeof...(Indices) - Indices - 1]...>();
    }
}
template<typename T, T... N>
constexpr auto reverse_sequence(std::integer_sequence<T, N...> sequence) {
    return detail::reverse_sequence_helper(sequence,
                                           std::make_index_sequence<sizeof...(N)>());
}

if C++20 is available, it can be reduced to this function with the help of templated lambdas:

template<typename T, T... N>
constexpr auto reverse_sequence(std::integer_sequence<T, N...> sequence) {
    constexpr auto array = std::array { N... };
 
    auto make_sequence = [&]<typename I, I... Indices>(std::index_sequence<Indices...>) {
        return std::integer_sequence<T, array[sizeof...(Indices) - Indices - 1]...>();
    };
    return make_sequence(std::make_index_sequence<sizeof...(N)>());
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文