Как можно удалить тип из пакета параметров шаблона?

Я ищу способ удалить (пусть теперь все вхождения) тип из пакета параметров шаблона. Конечным результатом будет структура, которая выглядит так:

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 недействительна С++

Повторение

На всякий случай это полезно для ответа, некоторые другие проблемы при его решении

  • Можно утверждать, что pack вообще не полезен. Вместо этого мы могли бы перемещаться вокруг структуры RemoveT, создавая новый RemoveT, который содержит только те типы, которые необходимы. Затем проблема преобразуется при извлечении типов из структуры
  • Мы могли бы создать пары типов, которые имитируют поведение typelists и используют для этого более рекурсивный подход.

Нижняя линия

Для переменных типов Ts и типа T: Могу ли я создать Us из Ts ommiting T?

Ответ 1

Ниже приведен нерекурсивный и прямой способ удаления 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");
}

Живой пример

Ответ 2

Следующее может помочь:

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

Ответ 3

Сначала переместите все имена шаблонов в список. Возможно, есть способ указать имя шаблона и список параметров, задающих этот шаблон с параметрами, но я не смог его понять:

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