[英]Matching a C++ lambda expression in templates
我正在尝试匹配 C++ 模板中的可调用对象,并根据作为参数接收的可调用对象的类型提供不同的实现。
我有以下模板函数:
template<class Ret, class... Args>
void fun(std::function<Ret(Args...)> f) {}
template<class Ret, class... Args>
void fun(Ret(*f)(Args...)) {}
它们接受std::function
对象和普通函数指针,并正确推导出它们的返回Ret
和参数Args
类型。 但是,我很难传递匿名 lambda 表达式,因为它们与上面的任何模板都不匹配。
调用类似的东西
fun([](int x, int y){return x + y;})
导致编译错误。 实现接受匿名 lambda 函数的模板表达式的正确方法是什么? 也许一种方法是检查传递的类是否具有operator()
方法?
转换发生在模板参数替换之后。 lambda 的类型不是std::function
,而是匿名类型。 实际上,您将收到一个匿名 lambda 以接收任何可调用对象。
似乎您担心的是限制接收到的对象来定义operator()
。 这个问题很容易用表达式 sfinae 解决。 但是,由于您没有收到参数,因此很难检查表达式是否有效。
这不是一个通用示例,但它适用于任何没有auto
作为其参数之一的 lambda,或者任何没有重载operator()
对象:
template<typename F>
auto fun(F f) -> void_t<decltype(&T::operator())> {
// ...
}
void_t
实现如下:
template<typename...>
using void_t = void;
decltype
的表达式必须有效才能使函数存在。
如果您希望代码使用更多类型,则必须提供可以指定参数的重载。 该检查现在很容易实现:
// Another overload of your function
template<typename F, typename... Args>
auto fun(F f) -> void_t<decltype(f(std::declval<Args>()...)> {
// ...
}
这样,它也适用于泛型 lambda 和重载运算符。
这是有效的 C++ 代码,C++14 级别的 gcc 6.1.1 将支持我:
template<typename F>
void foo(F &&f)
{
}
void bar()
{
auto lambda=[](auto a, auto b) {};
foo(lambda);
}
如您所见,模板不可能推导出 lambda 的参数。 lambda 的参数类型在使用之前是未知的。
您可以推断出某个东西有一个operator()
,正如另一个答案所示,但就目前而言,这已经差不多了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.