是否可以确定可调用对象是否为谓词(即 returns bool)?

Is it possible to determine if a callable is a predicate (i.e. returns bool)?

尝试像这样重写谓词组合器

auto constexpr all = [](auto const&... predicates){
    return [predicates...](auto const&... x){
        return (predicates(x...) && ...);
    };
};

的小泛化),当使用 non-predicates/predicates 和不同的 arities/arguments 时,它会给出有意义的错误,我开始写这样的东西:

template<typename T, typename = void>
struct IsPredicate : public std::false_type {};

template<typename T>
struct IsPredicate<T, std::enable_if_t<std::is_same_v<bool, return_type_of_callable_T>, void>>
  : public std::true_type {};

然后我盯着它看了一会儿...如果我什至不知道如何调用它,我如何检查函数的 return 类型?

我看到了这个:

所以我的问题是:是否有可能确定任意可调用对象的 return 类型?

我最感兴趣的是 C++17 的答案,但是,为什么不呢?我还想知道 C++20 的概念在这方面提供了什么。

无法为您提供 C++17 的答案,但由于您还询问了概念:

requires 表达式表示 () 运算符重载并且 returns 是 bool。我认为经典意义上的谓词有两个参数,但这个概念可以很容易地扩展到 fo 来满足这个要求。

template<typename T>
concept IsPredicate =
    requires(T a) {
        { a() } -> std::same_as<bool>;
    };

如果不指定参数类型(通常通过提供实际参数来完成),您无法确定可调用对象的 return 类型,因为 return 类型可能取决于参数类型。 “decltype(potential_predicate)”不起作用,但“decltype(potential_predicate(args...))”是另一回事。

第一个将是可调用本身的类型(无论是指向函数的指针还是 class 类型或其他类型),而第二个将生成可调用表达式的 return 类型。

So my question is: is it even possible to determine the return type of an arbitrary callable?

没有。您只能在非常狭窄的情况下这样做:

  • 可调用对象是指向成员数据的指针/指向成员函数的指针
  • 可调用函数是 pointer/reference 函数
  • 可调用对象是一个函数对象,具有一个非模板的非重载函数调用运算符,并且没有到函数的转换函数 pointers/reference

就是这样。如果你有一个函数对象,其调用运算符要么是重载的,要么是模板,你无法真正弄清楚它的 return 类型是什么。它的 return 类型可能取决于它的参数类型,您可能无法知道参数类型可能是什么。也许它是一个调用运算符模板,它只接受一些您无法知道的特定类型,但它这些类型的谓词吗?

你能做的最好的事情就是推迟检查,直到你知道参数是什么。然后 C++20 已经有了适合你的概念 (predicate):

inline constexpr auto all = []<typename... Ps>(Ps const&... predicates){
    return [=]<typename... Xs>(Xs const&... x)
        requires (std::predicate<Ps const&, Xs const&...> && ...)
    {
        return (std::invoke(predicates, x...) && ...);
    };
};

请注意,您应该使用 std::invoke 以允许指向成员的指针也作为谓词(这就是 std::predicate 检查的内容)。