C ++编译时谓词,用于测试是否可以使用类型为T的参数调用类型为F的可调用对象 [英] C++ compile-time predicate to test if a callable object of type F can be called with an argument of type T

查看:150
本文介绍了C ++编译时谓词,用于测试是否可以使用类型为T的参数调用类型为F的可调用对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个编译类型的函数,给定任何可调用的对象 f (函数,lambda表达式,函数对象,...)和类型<如果 f 可以使用类型 T 的参数调用,则code> T

I would like to create a compile-type function that, given any callable object f (function, lambda expression, function object, ...) and a type T, evaluates to true, if f can be called with an argument of type T, and false if it cannot.

例如:

void f1(int) { ... }
void f2(const std::string&) { ... }

assert( is_callable_with<int>(f1));
assert(!is_callable_with<int>(f2));

我认为巧妙使用SFINAE规则可以实现这一点。可能有点像这样:

I'm thinking that a clever use of the SFINAE rule could achieve this. Possibly somehow like this:

template<typename T, typename F>
constexpr bool is_callable_with(F&&, typename std::result_of<F(T)>::type* = nullptr) {
  return true;
}

template<typename T, typename F>
constexpr bool is_callable_with(F&&) {
  return false;
}

但这不起作用,因为如果 F 是可调用 T ,两个重载都参与重载解析,并且有歧义。我想重写它,所以在积极的情况下,第一个重载将选择重载决议超过第二个。

But this doesn't work, because if F is callable with T, both overloads participate in the overload resolution and there is an ambiguity. I'd like to rewrite it so in the positive case, the first overload would be picked by the overload resolution over the second one. Not sure if I'm even on the right track here though.

推荐答案

保罗答案,但遵循标准的SFINAE测试模式。再次是具有任意参数类型的一般性状 A ...

A variant of Paul's answer, but following the standard SFINAE test pattern. Again a generic trait with arbitrary parameter types A...:

struct can_call_test
{
    template<typename F, typename... A>
    static decltype(std::declval<F>()(std::declval<A>()...), std::true_type())
    f(int);

    template<typename F, typename... A>
    static std::false_type
    f(...);
};

template<typename F, typename... A>
using can_call = decltype(can_call_test::f<F, A...>(0));

然后按照您的要求执行 constexpr

Then a constexpr function as you requested:

template<typename T, typename F>
constexpr bool is_callable_with(F&&) { return can_call<F, T>{}; }

检查 live示例

这将使用函数,lambda表达式或函数对象与任意数量的参数,但对于(指针)成员函数,你必须使用 std :: result_of< F(A ...)>

This will work with functions, lambda expressions, or function objects with arbitrary number of arguments, but for (pointers to) member functions you'll have to use std::result_of<F(A...)>.

UPDATE

以下为 can_call 具有 std :: result_of 的好的函数签名语法:

Below, can_call has the nice "function signature" syntax of std::result_of:

template<typename F, typename... A>
struct can_call : decltype(can_call_test::f<F, A...>(0)) { };

template<typename F, typename... A>
struct can_call <F(A...)> : can_call <F, A...> { };

可以使用

template<typename... A, typename F>
constexpr can_call<F, A...>
is_callable_with(F&&) { return can_call<F(A...)>{}; }

其中我也做了 is_callable_with variadic(我不明白为什么它应该只限于一个参数),并返回与 can_call 相同的类型,而不是 bool

where I've also made is_callable_with variadic (I can't see why it should be limited to one argument) and returning the same type as can_call instead of bool (thanks Yakk).

再次,这里的实例

这篇关于C ++编译时谓词,用于测试是否可以使用类型为T的参数调用类型为F的可调用对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆