如何在类型列表中移动类型?

用户名

使用std::tuple<>我的类型列表,我希望能够有一个模板:

template<std::size_t i_src, std::size_t i_dst, class Tuple>
struct tuple_shift
{
    // implementation
};

包含的type别名将返回移位的类型列表,以便编译以下示例:

// move type at i_src to i_dst and shift the types
// i_src = 1, i_dst = 3 : right to left shift

using tuple_t          = std::tuple<int, char, long, double, float>; // before
using expected_tuple_t = std::tuple<int, long, double, char, float>; // after

using result_tuple_t = tuple_shift<1, 3, tuple_t>::type; // actual result

static_assert( std::is_same<expected_tuple_t, result_tuple_t>::value, "!" );

示例用例:类型列表的稳定排序。


这是我的解决方案,与TC解决方案相比,它在简洁性方面又是另一个星系,但它避免了必须对每个索引进行比较的情况。这取决于模板推论的工作。

这实际上是部分解决方案。完整的解决方案专门用于在i_src == i_dst时正确扩展序列i_dst < i_src它通过生成索引序列,然后将其全部合并为一个来工作。

对于i_src = 1, i_dst = 3,其中序列为<0, 1, 2, 3, 4>,将生成以下内容(以伪代码):

left_index_seq    = <0>
shifted_index_seq = <2, 3>
right_index_seq   = <4>

然后将其扩展为:

sequence = <left_index_seq, shifted_index_seq, i_src, right_index_seq>
         = <<0>, <2, 3>, 1, <4>>
         = <0, 2, 3, 1, 4>

执行

#include <tuple>
#include <utility>

template<std::size_t offset, class IndexSequence>
struct index_sequence_offset;

template<std::size_t offset, std::size_t... Is>
struct index_sequence_offset<offset, std::index_sequence<Is...>>
{
    using type = std::index_sequence<( offset + Is )...>;
};

template<std::size_t offset, class IndexSequence>
using make_index_sequence_offset = typename index_sequence_offset
<
    offset, IndexSequence
>::type;

template<class IndexSequence>
struct index_sequence_size;

template<std::size_t... Is>
struct index_sequence_size<std::index_sequence<Is...>>
    : std::integral_constant<std::size_t, sizeof...( Is )>
{};

template<std::size_t i_src, std::size_t i_dst, class Tuple>
struct tuple_shift_indices
{
private:
    template<class LIPack, class SIPack, class RIPack>
    struct tuple_shift_indices_impl;

    template<std::size_t... l_is, std::size_t... s_is, std::size_t... r_is>
    struct tuple_shift_indices_impl
    <
        std::index_sequence<l_is...>,
        std::index_sequence<s_is...>,
        std::index_sequence<r_is...>
    >
    {
        using type = std::index_sequence<l_is..., s_is..., i_src, r_is...>;
    };

public:
    using type = typename tuple_shift_indices_impl
    <
        std::make_index_sequence<i_src>,
        make_index_sequence_offset<i_src + 1, std::make_index_sequence<i_dst - i_src>>,
        make_index_sequence_offset<std::tuple_size<Tuple>::value - 1, std::make_index_sequence<i_dst - i_src - 1>>
    >::type;
};

template<std::size_t i_src, std::size_t i_dst, class Tuple>
struct tuple_shift
{
private:
    template<class IndexSequence>
    struct tuple_shift_impl;

    template<std::size_t... is>
    struct tuple_shift_impl<std::index_sequence<is...>>
    {
        using type = std::tuple<std::tuple_element_t<is, Tuple>...>;
    };

public:
    using type = typename tuple_shift_impl
    <
        typename tuple_shift_indices<i_src, i_dst, Tuple>::type
    >::type;
};
TC

一个constexpr函数来计算实际的索引映射:

constexpr std::size_t old_index(std::size_t new_index, std::size_t src, std::size_t dst) {
    if(new_index == dst) return src;
    if(src < dst && new_index >= src && new_index < dst) return new_index + 1;
    if(src > dst && new_index <= src && new_index > dst) return new_index - 1;
    return new_index;
}

这样的实现是微不足道的。

template<std::size_t i_src, std::size_t i_dst,
         class Tuple, class = std::make_index_sequence<std::tuple_size_v<Tuple>>>
struct tuple_shift;

template<std::size_t i_src, std::size_t i_dst,
         class Tuple, std::size_t... Is>
struct tuple_shift<i_src, i_dst, Tuple, std::index_sequence<Is...>>
{
    using type = std::tuple<std::tuple_element_t<old_index(Is, i_src, i_dst), Tuple>...>;
};

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在PyCharm中移动文件类型而不是特定文件?

来自分类Dev

如何在c#中移动列表中的项目子集?

来自分类Dev

如何从实现Drop的结构中移动类型未实现Default的字段?

来自分类常见问题

如何在Pygame中移动矩形

来自分类Dev

如何在MFC中移动窗口?

来自分类Dev

如何在Android IDE中移动文件

来自分类Dev

如何在Eigen中移动矩阵?

来自分类Dev

如何在QtDesigner中移动项目?

来自分类Dev

如何在输入字段中移动文本?

来自分类Dev

如何在多维数组中移动元素?

来自分类Dev

如何在Realm中移动对象

来自分类Dev

如何在flexbox中移动项目?

来自分类Dev

如何在pygame中移动时射击

来自分类Dev

如何在pywinauto中移动UIAWrapper窗口?

来自分类Dev

如何在QAbstractItemView中移动QWidget?

来自分类Dev

如何在Pygame中移动矩形

来自分类Dev

如何在Pygame中移动表面

来自分类Dev

如何在GNU屏幕中移动窗口

来自分类Dev

如何在bash中移动数组值

来自分类Dev

如何在Android中移动多个视图?

来自分类Dev

如何在Eigen中移动矩阵?

来自分类Dev

iOS:如何在UIImageView中移动图像

来自分类Dev

JavaFX:如何在GridPane中移动元素?

来自分类Dev

如何在xml中移动图像视图

来自分类Dev

如何在Git中移动多个目录?

来自分类Dev

如何在GNU / Linux中移动分区?

来自分类Dev

如何在Laravel Eloquent中移动行?

来自分类Dev

如何在输入字段中移动文本?

来自分类Dev

如何在GNOME Classic中移动时钟?