是否可以确定可调用对象是否为谓词(即 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 类型?
我看到了这个:
- 我什至无法将
decltype(overloaded_predicate_function)
传递给 IsPredicate
,因为模板类型推导不会发生在重载的名称中,
- 即使我只谈论函数对象,第一个要点的问题也适用于
operator()
,以防它过载。
所以我的问题是:是否有可能确定任意可调用对象的 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
检查的内容)。
尝试像这样重写谓词组合器
auto constexpr all = [](auto const&... predicates){
return [predicates...](auto const&... x){
return (predicates(x...) && ...);
};
};
(
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 类型?
我看到了这个:
- 我什至无法将
decltype(overloaded_predicate_function)
传递给IsPredicate
,因为模板类型推导不会发生在重载的名称中, - 即使我只谈论函数对象,第一个要点的问题也适用于
operator()
,以防它过载。
所以我的问题是:是否有可能确定任意可调用对象的 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
检查的内容)。