Типы фильтров в пакете параметров
Я пытаюсь создать отфильтрованный тип вариативного шаблона / пакета параметров, а также сохранить порядок.
// example what im trying to accomplish
template<typename... Args>
struct query
{
using filtered = typename filtered<std::is_integral_v, Args...>
}
В этом примере фильтр будет фильтровать все целые типы, например.
query<int, A, B>::filtered == query<A, B>::filtered
Как я могу создать такую утилиту или что-то, что достигло бы тех же результатов
3 ответа
Решение
Комментарий от @Jarod42 имеет демонстрацию с рабочим кодом
#include <tuple>
#include <type_traits>
template<template<class> class, template<class...> class, class...>
struct filter;
template<template<class> class Pred, template<class...> class Variadic>
struct filter<Pred, Variadic>
{
using type = Variadic<>;
};
template<template<class> class Pred,
template<class...> class Variadic,
class T,
class... Ts>
struct filter<Pred, Variadic, T, Ts...>
{
template<class, class>
struct Cons;
template<class Head, class... Tail>
struct Cons<Head, Variadic<Tail...>>
{
using type = Variadic<Head, Tail...>;
};
using type = typename std::conditional<
Pred<T>::value,
typename Cons<T, typename filter<Pred, Variadic, Ts...>::type>::type,
typename filter<Pred, Variadic, Ts...>::type>::type;
};
И интеграция с моим примером
template<typename... Args>
struct query
{
using filtered = filter<std::is_integral, std::tuple, Args...>::type
}
С Boost.Mp11 это короткий однострочный (как всегда):
using filtered = mp_filter<std::is_integral, mp_list<Args...>>;
Обратите внимание: если вы хотите, чтобы это был std::tuple
, это:
using filtered = mp_filter<std::is_integral, std::tuple<Args...>>;
Вы можете избежать рекурсии, используя std::tuple_cat()
#include <type_traits>
#include <tuple>
template <template <typename> class F, typename T>
std::enable_if_t<true == F<T>::value, std::tuple<>> filter ();
template <template <typename> class F, typename T>
std::enable_if_t<false == F<T>::value, std::tuple<T>> filter ();
template <typename...>
struct query;
template <typename ... Ts>
query<Ts...> deTuple (std::tuple<Ts...>);
template <template <typename> class F, typename ... Ts>
struct filtered
{ using type = decltype(std::tuple_cat(filter<F, Ts>()...)); };
template<typename... Args>
struct query
{
using filtered = decltype(deTuple(std::declval<
typename filtered<std::is_integral, Args...>::type>()));
};
class A {};
class B {};
int main ()
{
using T1 = typename query<int, A, B>::filtered;
using T2 = query<A, B>;
static_assert( std::is_same_v<T1, T2> );
}