如何为类型列表谓词创建 C++20 概念?

How to create C++20 concept for typelist predicate?

我开始学习 C++20 的概念。我想为类型列表的过滤谓词创建一个 concept

假设,有一个这样定义的类型列表:

template <typename ...TYPE>
struct List {
};

还有Filter,它可以根据谓词过滤类型列表。一个可能的定义是这样的:

template <template <typename> typename PREDICATE, typename LIST>
struct Filter {
    using result = List<...>; // some implementation here
};

这意味着,对于每个 LISTTYPE 参数,必须评估 PREDICATE<TYPE>::value(它是一个 bool 值),如果它是 true,则Filter::result必须包含TYPE.

现在,我如何为 PREDICATE 创建一个 concept,所以 Filter 将只接受它,如果它包含一个 value 成员(对于所有 TYPE 专长,在 LIST)?

我的意思是,对于这个 MyPredicateconcept 应该只允许用 LIST 实例化 Filter,除了 some_type1some_type2:

template <typename TYPE>
struct MyPredicate;

template <>
struct MyPredicate<some_type1> {
    static constexpr bool value = true;
};

template <>
struct MyPredicate<some_type2> {
    static constexpr bool value = false;
};

Filter<MyPredicate, List<some_type1, some_type2>>::result x; // here, x should have the type List<some_type1>
Filter<MyPredicate, List<int>>::result y; // should not compile, as MyPredicate<int> isn't defined

您有检查单个实例化的概念:

template <typename T>
concept nested_value = std::same_as<decltype(T::value), bool>;

你可以在折叠表达式中使用:

template <template <typename> class Pred, typename List>
struct Filter;

template <template <typename> class Pred, template <typename...> class L, typename... Ts>
    requires (nested_value<Pred<Ts>> && ... )
struct Filter<Pred, L<Ts...>> {
    // ...
};

或者你基本上可以在一个概念中做同样的事情:

template <template <typename> class Pred, typename List>
struct all_nested_impl : std::false_type { };

template <template <typename> class Pred, template <typename...> class L, typename... Ts>
struct all_nested_impl<Pred, L<Ts...>>
    : std::bool_constant<(nested_value<Pred<Ts>> && ...)>
{ };

template <template <typename> class Pred, typename List>
concept all_nested = all_nested_impl<Pred, List>::value;

template <template <typename> class Pred, typename List>
    requires all_nested<Pred, List>
struct Filter;

或者如果你只是翻转参数,你就可以写:

template <template <typename> class Pred, all_nested<Pred> List>
struct Filter;