我想创建一个编译类型的函数,给定任何可调用对象f
(函数,lambda表达式,函数对象,...)和T
类型,如果f
可以用T
类型的参数调用,则计算结果为true,如果不能,则为false。
范例:
void f1(int) { ... }
void f2(const std::string&) { ... }
assert( is_callable_with<int>(f1));
assert(!is_callable_with<int>(f2));
我认为巧妙地使用SFINAE规则可以实现这一点。可能是这样的:
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
调用,则两个重载都参与重载解析,并且存在二义性。我想重写它,所以在积极的情况下,第一个重载将被重载决议选中,而不是第二个。我甚至不确定我是否在正确的轨道上。
4条答案
按热度按时间lf5gs5x21#
Paul's answer的变体,但遵循标准SFINAE测试模式。同样是一个带有任意参数类型
A...
的泛型trait:然后按照您的要求执行
constexpr
函数:检查live example。
这将适用于函数,lambda表达式或具有任意数量参数的函数对象,但对于(指向)成员函数,您必须使用
std::result_of<F(A...)>
。更新
下面,
can_call
具有std::result_of
的漂亮的“函数签名”语法:被这样利用
在这里,我还使
is_callable_with
变元(我不明白为什么它应该被限制为一个参数),并返回与can_call
相同的类型,而不是bool
(感谢Yakk)。再一次,live example here。
vd2z7a6w2#
我会先创建一个类型trait:
如果你愿意,你可以把它变成一个函数:
jhdbpxl93#
它基本上与
Paul
发布的解决方案相同,我只是更喜欢使用conditional<true, void, decltype( ... ) >
而不是holder
类来避免命名空间污染。hts6caw34#
在C++ 17中,现在是std::is_invocable:
我花了一段时间才找到,可以为某人保存一些时间。