如何从模板参数包中删除类型

How can a type be removed from a template parameter pack?

本文关键字:包中 删除 类型 参数      更新时间:2023-10-16

我正在寻找一种方法从模板参数包中删除(假设现在所有出现的)类型。最终的结果将是如下所示的结构体:

template<typename T, typename...Ts>
struct RemoveT
{
    using type = /* a new type out of Ts that does not contain T */
}

假设边际情况RemoveT<int, int>将通过返回void来处理(不在后面的代码中处理)。我的初始设计看起来像这样:

// --------------------------------------------------------------
// 1. A "way" of typedefing variadic number of types ------------
template<typename...Ts>
struct pack { 
    using type = Ts; 
};
// --------------------------------------------------------------
// --------------------------------------------------------------
template<typename T, typename...Ts> struct RemoveT;
template<typename T, typename T1, typename...Ts>
struct RemoveT {
    using type = typename pack<T1, typename RemoveT<T, Ts...>::type>::type;
};
template<typename T, typename T1>
struct RemoveT<T, T1> { 
    using type = T1; 
};
template<typename T, typename...Ts>
struct RemoveT<T, T, Ts...> {
    using type = typename RemoveT<Ts...>::type;
};
// --------------------------------------------------------------

现在我甚至不能开始测试这段代码因为 pack结构是无效的c++

重复

如果这是一个有帮助的答案,一些关于解决它的其他想法

  • 有人可能会说pack根本没用。我们可以移动RemoveT结构体,创建一个只包含所需类型的新RemoveT。然后问题转变为从结构体
  • 中提取类型。
  • 我们可以创建模仿类型列表行为的类型对,并在这方面采用更递归的方法。

底线

对于可变类型TsT: 我可以在Ts中创建Us并提交T吗?

下面提供了一种非递归的直接方法来从Ts...中删除T,并且像Jarod42的解决方案一样,产生std::tuple<Us...>,但不需要使用typename ...::type:

#include <tuple>
#include <type_traits>
template<typename...Ts>
using tuple_cat_t = decltype(std::tuple_cat(std::declval<Ts>()...));
template<typename T, typename...Ts>
using remove_t = tuple_cat_t<
    typename std::conditional<
        std::is_same<T, Ts>::value,
        std::tuple<>,
        std::tuple<Ts>
    >::type...
>;

int main()
{
    static_assert(std::is_same<
        remove_t<int, int, char, int, float, int>,
        std::tuple<char, float>
    >::value, "Oops");
}
<<p> 生活例子/strong>

以下内容可能有所帮助:

namespace detail
{
    template <typename T, typename Tuple, typename Res = std::tuple<>>
    struct removeT_helper;

    template<typename T, typename Res>
    struct removeT_helper<T, std::tuple<>, Res>
    {
        using type = Res;
    };
    template<typename T, typename... Ts, typename... TRes>
    struct removeT_helper<T, std::tuple<T, Ts...>, std::tuple<TRes...>> :
        removeT_helper<T, std::tuple<Ts...>, std::tuple<TRes...>>
    {};
    template<typename T, typename T1, typename ...Ts, typename... TRes>
    struct removeT_helper<T, std::tuple<T1, Ts...>, std::tuple<TRes...>> :
        removeT_helper<T, std::tuple<Ts...>, std::tuple<TRes..., T1>>
    {};
}
template <typename T, typename...Ts> struct RemoveT
{
    using type = typename detail::removeT_helper<T, std::tuple<Ts...>>::type;
};
static_assert(std::is_same<std::tuple<char, float>,
                        typename RemoveT<int, int, char, int, float, int>::type>::value, "");

首先,将所有特定的模板名称移到一个列表中。可能有一种方法可以指定模板名称和参数列表,并为该模板提供参数,但我还没能弄清楚:

template <typename...TArgs> struct TypeList
{
    typedef std::tuple<TArgs...> tuple_type;
    // whatever other types you need
};

接下来,定义加法:

template<typename T, typename TList> struct AddT;
template<typename T, typename ... TArgs>
struct AddT< T, TypeList<TArgs...> >
{
    typedef TypeList<T, TArgs... > type;
};

然后定义移除:

template<typename R, typename ... TArgs> struct RemoveT;
template<typename R>
struct RemoveT<R>
{
    typedef TypeList<> type;
};
template<typename R, typename T, typename ...TArgs>
struct RemoveT<R, T, TArgs...>
{
    typedef typename std::conditional
        < std::is_same<R, T>::value
        , typename RemoveT<R, TArgs...>::type
        , typename AddT<T, typename RemoveT<R, TArgs...>::type>::type
        >::type type;
};

最后,测试:

int result = 0;
result = std::is_same
    < std::tuple<long,double>
    , RemoveT<int, int, long, int, double, int>::type::tuple_type
    >::value;
assert ( result );