试图重写这样的谓词组合器
auto constexpr all = [](auto const&... predicates){
return [predicates...](auto const&... x){
return (predicates(x...) && ...);
};
};
(this 的小泛化)以某种方式在输入具有不同参数/参数的非谓词/谓词时会产生有意义的错误,我开始写这样的东西:
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 在这方面提供了什么概念。
答案 0 :(得分:3)
所以我的问题是:甚至可以确定任意可调用对象的返回类型吗?
没有。您只能在非常狭窄的情况下执行此操作:
就是这样。如果你有一个函数对象,它的调用运算符要么是重载的,要么是模板,你真的无法弄清楚它的返回类型是什么。它的返回类型可能取决于其参数类型,您可能无法知道参数类型是什么。也许这是一个调用运算符模板,它只接受一些您无法了解的特定类型,但它是这些类型的谓词?
你能做的最好的事情就是推迟检查,直到你知道什么是参数。然后 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
检查的内容)。
答案 1 :(得分:1)
如果不指定参数类型(通常通过提供实际参数来完成),则无法确定可调用对象的返回类型,因为返回类型可能取决于参数类型。 “decltype(potential_predicate)”不起作用,但“decltype(potential_predicate(args...))”是另一回事。
第一个将是可调用本身的类型(函数指针或类类型或其他类型),而第二个将生成可调用表达式的返回类型。
答案 2 :(得分:0)
不能给你一个 C++17 的答案,但因为你也问了概念:
requires
表达式表明 ()
运算符已重载并返回 bool
。我认为经典意义上的谓词需要两个参数,但这个概念可以很容易地扩展到满足这个要求。
template<typename T>
concept IsPredicate =
requires(T a) {
{ a() } -> std::same_as<bool>;
};