C++ 编译时谓词,用于测试是否可以使用 T 类型的参数调用 F 类型的可调用对象

标签 c++ templates c++11 template-meta-programming

我想创建一个编译类型函数,给定任何可调用对象 f(函数、lambda 表达式、函数对象...)和类型 T,如果可以使用 T 类型的参数调用 f,则计算结果为 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 调用,则两个重载都参与重载解析,并且存在歧义。我想重写它,所以在肯定的情况下,第一个重载将被重载决议选择而不是第二个重载。不过,我不确定我是否走在正确的轨道上。

最佳答案

Paul's answer 的变体,但遵循标准 SFINAE 测试模式。再次是具有任意参数类型的通用特征 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按您的要求运行:

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

检查 live example .

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


更新

下面,can_call具有 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可变参数(我不明白为什么应该限制为一个参数)并返回与 can_call 相同的类型而不是 bool (感谢 Yakk)。

再次,live example here .

关于C++ 编译时谓词,用于测试是否可以使用 T 类型的参数调用 F 类型的可调用对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22882170/

相关文章:

c++ - 加载共享库时出错

html - 如何在 CKEditor 中创建自定义 html 模板?

c++ - 如何使用模板方法避免循环依赖

c++ - 在 C++ 中编码时无法在 VS Code 中使用 auto 关键字

c++ - Visual Studio 11(测试版)中的强类型枚举类

c++ - 警告 : auto-importing has been activated without --enable-auto-import specified on the command line

c++ - 将附加参数包装到 c++11 中的可变参数包

c++ - 即使包含文件也编译错误

c++ - 如何新建模板特化类对象?

c++ - 将 c++0x 线程与 gio GCancellable 混合使用是否合法?