是否可以确定可调用项是否为谓词(即返回bool)

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

本文关键字:是否 bool 谓词 返回 调用      更新时间:2024-05-23

试图重写类似的谓词组合子

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

(对此进行了一点概括(当使用具有不同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 {};

然后我盯着它看了一会儿。。。如果我甚至不知道如何调用函数,我该如何检查函数的返回类型?

我看到这个:

  • 我甚至无法将decltype(overloaded_predicate_function)传递给IsPredicate,因为模板类型推导不能用重载名称进行
  • 即使我只谈论函数对象,第一个要点的问题也可能适用于operator(),以防它过载

所以我的问题是:是否有可能确定任意可调用函数的返回类型?

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

所以我的问题是:是否有可能确定任意可调用函数的返回类型?

否。你只能在非常狭窄的情况下这样做:

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

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

你能做的最好的事情就是推迟检查,直到你知道什么是论据。然后C++20已经为您提供了概念(谓词(:

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检查的内容(。

如果不指定参数类型(通常通过提供实际参数来完成(,就无法确定可调用函数的返回类型,因为返回类型可能取决于参数类型"decltype(potential_predicate(";不会起作用,但";decltype(potential_predicate(args…((";是另一回事。

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

不能给你一个C++17的答案,但因为你也要求概念:

requires表达式表示()运算符过载,并返回一个bool。我认为一个经典意义上的谓词需要两个参数,但这个概念也可以很容易地扩展到满足这个要求。

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