Фильтрация типов пакета параметров

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

/** Filter a parameter pack */    
template <template <class> class,
          template <class...> class,
          class...>
struct filter;
template <template <class> class Pred, template <class...> class Variadic>
struct filter<Pred, Variadic> : Variadic<>
{};
template <template <class> class Pred,
          template <class...> class Variadic,
          class T, class... Ts>
struct filter<Pred, Variadic, T, Ts...>
{
    // FIXME: this just stops at first T where Pred<T> is true
    using type = typename std::conditional<
        Pred<T>::value,
        Variadic<T, Ts...>,    // can't do: Variadic<T, filter<...>>
        filter<Pred, Variadic, Ts...> >::type;
};

Как видите, я не нашел способа «извлечь» пакет параметров из остальных отфильтрованных типов.

Заранее спасибо!


person scry    schedule 21.08.2013    source источник


Ответы (1)


Это должно быть довольно прямолинейно. В основе должно быть что-то вроде этого:

template <typename...> struct filter;

template <> struct filter<> { using type = std::tuple<>; };

template <typename Head, typename ...Tail>
struct filter<Head, Tail...>
{
    using type = typename std::conditional<Predicate<Head>::value,
                               typename Cons<Head, typename filter<Tail...>::type>::type,
                               typename filter<Tail...>::type
                          >::type;
};

Вам просто нужно Cons<T, Tuple>, которое превращает T, std::tuple<Args...> в std::tuple<T, Args...>, и вам нужно передать предикат (оставлено в качестве упражнения). Cons может выглядеть так:

template <typename, typename> struct Cons;

template <typename  T, typename ...Args>
struct Cons<T, std::tuple<Args...>>
{
    using type = std::tuple<T, Args...>;
};

Результатом filter<Args...>::type будет std::tuple<Brgs...>, где Brgs... — это пакет, состоящий только из тех типов в Args..., для которых выполняется предикат.

person Kerrek SB    schedule 21.08.2013
comment
Что-то я до сих пор не понимаю, но ошибки компилятора не помогают. Я разместил здесь ideone.com/USTnJR, если вы не возражаете, посмотрите еще раз - это не так. кажется правильным отредактировать оригинал. - person scry; 22.08.2013
comment
В этой версии была другая проблема, используйте эту: ideone.com/eh3Epd. Как видите, члены ::type для filter и Cons не распознаются как типы. - person scry; 22.08.2013
comment
@roysc: Cons должен быть специализирован для кортежей. Позвольте мне отредактировать это. [Редактировать:] Готово. Я также изменил основной шаблон, чтобы иметь правильный базовый вариант. - person Kerrek SB; 22.08.2013
comment
Потрясающий! Это в основном то, что у меня было - оказалось, мне нужно больше typename, чтобы помочь компилятору. - person scry; 22.08.2013
comment
@scry: Исправленная версия с дополнительными typename. - person Jarod42; 31.01.2020
comment
@Jarod42: Этот пост нуждается в дальнейшем редактировании? Не могли бы вы сделать или предложить один? - person Kerrek SB; 01.02.2020
comment
Вы даете рекомендации и проверяете, что OP в большинстве случаев удается включить рабочий код (с отсутствующим typename) в комментарии. Пользователь из другого вопроса скопируйте/вставьте свой код руководства и пожалуйтесь на проблему (отсутствует Predicate). Таким образом, предоставление окончательного результата (как указано в комментарии) было бы хорошо, ИМО. - person Jarod42; 03.02.2020