А теперь для чего-то совершенно другого ...
Я предлагаю разделить ваш «нормальный случай» (рекурсивный случай) на два разных случая: случай «истина» и случай «ложь».
К сожалению, для этого требуются дополнительные черты пользовательского типа check_first
template <typename, template <typename> class>
struct check_first : public std::false_type
{ };
template <typename H, typename ... T, template <typename> class P>
struct check_first<tl<H, T...>, P>
: public std::integral_constant<bool, P<H>::value>
{ };
Теперь вы можете написать filter_tl_impl
следующим образом
// declaration and ground case
template <typename I, typename O, template <typename> class P,
bool = check_first<I, P>::value>
struct filter_tl_impl
{ using type = O; };
// recursive-positive case
template <typename H, typename... T, typename... Ts,
template <typename> class P>
struct filter_tl_impl<tl<H, T...>, tl<Ts...>, P, true>
: public filter_tl_impl<tl<T...>, tl<Ts..., H>, P>
{ };
// recursive-negative case
template <typename H, typename... T, typename... Ts,
template <typename> class P>
struct filter_tl_impl<tl<H, T...>, tl<Ts...>, P, false>
: public filter_tl_impl<tl<T...>, tl<Ts...>, P>
{ };
Я также переписал filter_tl
как более простой using
template <typename TL, template <typename> class P>
using filter_tl = typename filter_tl_impl<TL, tl<>, P>::type;
, чтобы ваш исходный код стал
#include <type_traits>
// a type list
template <typename...>
struct tl;
template <typename, template <typename> class>
struct check_first : public std::false_type
{ };
template <typename H, typename ... T, template <typename> class P>
struct check_first<tl<H, T...>, P>
: public std::integral_constant<bool, P<H>::value>
{ };
// declaration and ground case
template <typename I, typename O, template <typename> class P,
bool = check_first<I, P>::value>
struct filter_tl_impl
{ using type = O; };
// recursive-positive case
template <typename H, typename... T, typename... Ts,
template <typename> class P>
struct filter_tl_impl<tl<H, T...>, tl<Ts...>, P, true>
: public filter_tl_impl<tl<T...>, tl<Ts..., H>, P>
{ };
// recursive-negative case
template <typename H, typename... T, typename... Ts,
template <typename> class P>
struct filter_tl_impl<tl<H, T...>, tl<Ts...>, P, false>
: public filter_tl_impl<tl<T...>, tl<Ts...>, P>
{ };
template <typename TL, template <typename> class P>
using filter_tl = typename filter_tl_impl<TL, tl<>, P>::type;
// Test code
using MyTypes = tl<char*, bool, char, int, long, void,
char*, bool, char, int, long, void,
char*, bool, char, int, long, void>;
using MyNumericTypes = filter_tl<MyTypes, std::is_arithmetic>;
static_assert(std::is_same_v<MyNumericTypes,
tl<bool, char, int, long,
bool, char, int, long,
bool, char, int, long>>);
int main ()
{ }