Как можно удалить тип из пакета параметров шаблона?
Я ищу способ удалить (пусть теперь все вхождения) тип из пакета параметров шаблона. Конечным результатом будет структура, которая выглядит так:
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 );