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

时间:2014-05-25 13:19:53

标签: c++ templates c++11 variadic-templates template-meta-programming

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

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;
};
// --------------------------------------------------------------

现在我甚至无法开始测试此代码,因为the pack structure is not valid C++

复现

以防这对答案有帮助,其他一些解决方法

  • 有人可能会说pack甚至根本没用。我们可以在RemoveT结构周围移动,创建一个仅包含所需类型的新RemoveT。然后,问题在从struct
  • 中提取类型时进行转换
  • 我们可以创建模仿类型列表行为的类型对,并对此采取更加递归的方法。

底线

对于可变类型Ts和类型T我可以从Us中创建Ts,忽略T吗? < / p>

3 个答案:

答案 0 :(得分:10)

以下提供了从T中删除Ts...的非递归和直接方法,并且与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");
}

Live example

答案 1 :(得分:8)

以下可能会有所帮助:

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, "");

答案 2 :(得分:2)

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

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 );