c++ - 如何在类型列表中移动类型?

标签 c++ template-meta-programming

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

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

A包含type alias 将返回转换后的类型列表,以便编译以下示例:

// 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 相比,它在简洁性方面处于另一个星系中的 solution ,但它避免了必须对每个索引进行比较;这取决于模板推导的工作。

这实际上是一个部分解决方案;完整的解决方案专门用于在 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;
};

最佳答案

用于计算实际索引映射的 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>...>;
};

关于c++ - 如何在类型列表中移动类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38032765/

相关文章:

c++ - QThread 线程间通信:连接到 &QThread::quit 与连接到 lambda [&thread] { thread->quit();} 的奇怪行为

c++ - c++一致性是否使用decltype来帮助模板推导?

c++ - 检查类型是否具有在 C++ 中定义的 [][]

c++ - 缩小 C++ 概念以排除某些类型

c++ - 应该弃用 std::list 吗?

c++ - 为已经转换的QGraphicsItem设置转换原点

c++ - 如何根据 is_nothrow_move_constructible<T> 声明包装类型 X<T> noexcept 的移动构造函数?

c++ - 如果递归深度很深,TMP 真的会更快吗?

具有负 vector 大小计算的 C++ pow 行为

c++ - 模板 :Name resolution:Dependent template arguments : -->can any one tell some more examples for this statement?