在可变参数模板列表中插入/删除类型(参数包) [英] Insert/remove type into variadic template list (parameter pack)

查看:74
本文介绍了在可变参数模板列表中插入/删除类型(参数包)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在可变参数模板类型列表(参数包)中实现基于索引的类型的插入和删除的最佳方法是什么?

What is the best way of implementing index-based insertion and deletion of a type in a variadic template type list (parameter pack)?

所需的代码/行为:

template<typename...> struct List { /* ... */ };

static_assert(is_same
<
    List<int, char, float>::Insert<int, 0>,
    List<int, int, char, float>
>());

static_assert(is_same
<
    List<int, char, float>::Insert<int, 2>,
    List<int, char, int, float>
>());

static_assert(is_same
<
    List<int, char, float>::Remove<0>,
    List<char, float>
>());

static_assert(is_same
<
    List<int, char, float>::Remove<1>,
    List<int, float>
>());

我尝试了一种基于回退最初为空列表中的参数的实现,但是很难读取/维护.参数与此类似:

I tried an implementation based on pushing back the arguments in an initially-empty list, but it was very hard to read/maintain. The parameters were similar to this:

template<typename T, int I, int ITarget, typename TResult> struct InsertImpl;

我不断地递增I直到它等于ITarget,将TResult中的现有类型(即List<...>)推回原位.当I等于ITarget时,我也将TResult中的T推回.

I constantly increment I until it equals ITarget, pushing back existing types in TResult, which is a List<...>. When I equals ITarget, I push back T in TResult as well.

删除类型具有类似的实现方式-不再在索引相等时回退两次,而是直接跳过该类型.

Removing a type had a similar implementation - instead of pushing back twice when the indices were equal, I simply skipped the type.

我笨拙的解决方案将在推入和弹出方面实现插入和移除.我认为,将前推等于Insert<0>并向后推等于Insert<size>会更优雅.从前面和后面弹出都一样.

My cumbersome solution would implement insertion and removal in terms of pushing and popping. I believe it would be more elegant to have pushing to the front equal to Insert<0> and pushing to the back equal to Insert<size>. The same applies for popping from the front and from the back.

是否有更好的方法? C ++ 14功能可以提供帮助吗?

推荐答案

自从您提到C ++ 14以来,这是另一个使用std::index_sequence的人.我认为该解决方案值得一提的主要原因是使用constexpr映射函数将类型放置在结果List中的位置.这使实现相对简单.

Since you mentioned C++14, here's another one making use of std::index_sequence. The main reason for which I think the solution is worth mentioning is the use of constexpr mapping functions to place the types in their positions in the resulting List. This makes the implementation relatively straightforward.

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

template<typename...> struct List;

constexpr std::size_t map_ins(std::size_t i, std::size_t from, std::size_t to)
{
   return i < to ? i : i == to ? from : i - 1;
}

template<typename, typename, std::size_t, typename...> struct ins_hlp;

template<std::size_t... Is, typename U, std::size_t N, typename... Ts> 
struct ins_hlp<std::index_sequence<Is...>, U, N, Ts...>
{
   static_assert(N <= sizeof...(Ts), "Insert index out of range");
   using type = List<std::tuple_element_t<map_ins(Is, sizeof...(Ts), N), std::tuple<Ts..., U>>...>;
};

constexpr std::size_t map_rem(std::size_t i, std::size_t idx)
{
   return i < idx ? i : i + 1;
}

template<typename, std::size_t, typename...> struct rem_hlp_2;

template<std::size_t... Is, std::size_t N, typename... Ts> 
struct rem_hlp_2<std::index_sequence<Is...>, N, Ts...>
{
   using type = List<std::tuple_element_t<map_rem(Is, N), std::tuple<Ts...>>...>;
};

template<std::size_t N, typename... Ts> struct rem_hlp
{
   static_assert(N < sizeof...(Ts), "Remove index out of range");
   using type = typename rem_hlp_2<std::make_index_sequence<sizeof...(Ts) - 1>, N, Ts...>::type;
};

template<typename... Ts> struct List
{
   template<typename U, std::size_t N> using Insert = typename ins_hlp<std::make_index_sequence<sizeof...(Ts) + 1>, U, N, Ts...>::type;
   template<std::size_t N> using Remove = typename rem_hlp<N, Ts...>::type;
};

很抱歉,但我没有找到另一种有意义的方式来格式化这些参数列表.

Sorry for the long lines, but I didn't find another meaningful way to format those argument lists.

Remove附加辅助程序的唯一原因是边界检查.如果不需要,Remove可以使用与Insert相同的模式.

The only reason for having an additional helper for Remove is bounds checking; if that's not needed, Remove can use the same pattern as Insert.

这篇关于在可变参数模板列表中插入/删除类型(参数包)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆