[英]Matching a C++ lambda expression in templates
I am trying to match callable objects in C++ templates and provide different implementations based on the type of callable object that is receives as an argument.我正在尝试匹配 C++ 模板中的可调用对象,并根据作为参数接收的可调用对象的类型提供不同的实现。
I have the following template functions:我有以下模板函数:
template<class Ret, class... Args>
void fun(std::function<Ret(Args...)> f) {}
template<class Ret, class... Args>
void fun(Ret(*f)(Args...)) {}
They accept std::function
objects and ordinary function pointers, and correctly deduce their return Ret
and argument Args
types.它们接受
std::function
对象和普通函数指针,并正确推导出它们的返回Ret
和参数Args
类型。 However, I am having difficulty passing anonymous lambda expressions as they do not match any of the templates above.但是,我很难传递匿名 lambda 表达式,因为它们与上面的任何模板都不匹配。
Calling something like调用类似的东西
fun([](int x, int y){return x + y;})
results in a compilation error.导致编译错误。 What is the correct way to implement a template expression that accepts anonymous lambda functions?
实现接受匿名 lambda 函数的模板表达式的正确方法是什么? Maybe one way is to check if the class that is being passed has an
operator()
method?也许一种方法是检查传递的类是否具有
operator()
方法?
Conversions happen after template argument substitution.转换发生在模板参数替换之后。 The type of a lambda is not
std::function
, but an anonymous type. lambda 的类型不是
std::function
,而是匿名类型。 Indeed, you'll have the receive an anonymous lambda in order to receive any callable object.实际上,您将收到一个匿名 lambda 以接收任何可调用对象。
It seems your concern is about restricting the object received to have the operator()
defined.似乎您担心的是限制接收到的对象来定义
operator()
。 This problem is easily solvable with expression sfinae.这个问题很容易用表达式 sfinae 解决。 However, since you're not receiving parameters, it will be harder to check if the expression is valid.
但是,由于您没有收到参数,因此很难检查表达式是否有效。
This is not a general example, but it will work for any lambda that does not have auto
as one of it's parameter, or any object that has operator()
not overloaded:这不是一个通用示例,但它适用于任何没有
auto
作为其参数之一的 lambda,或者任何没有重载operator()
对象:
template<typename F>
auto fun(F f) -> void_t<decltype(&T::operator())> {
// ...
}
With void_t
implemented as follow: void_t
实现如下:
template<typename...>
using void_t = void;
The expression inside the decltype
must be valid in order for the function to exist. decltype
的表达式必须有效才能使函数存在。
If you want your code to work with more types, you'll have to offer an overload that you can specify the parameters.如果您希望代码使用更多类型,则必须提供可以指定参数的重载。 The check is now trivial to implement:
该检查现在很容易实现:
// Another overload of your function
template<typename F, typename... Args>
auto fun(F f) -> void_t<decltype(f(std::declval<Args>()...)> {
// ...
}
That way, it will works for generic lambda and overloaded operators too.这样,它也适用于泛型 lambda 和重载运算符。
This is valid C++ code, and gcc 6.1.1 at C++14 level will back me up on this:这是有效的 C++ 代码,C++14 级别的 gcc 6.1.1 将支持我:
template<typename F>
void foo(F &&f)
{
}
void bar()
{
auto lambda=[](auto a, auto b) {};
foo(lambda);
}
As you can see, a template can't possibly deduce the arguments of a lambda.如您所见,模板不可能推导出 lambda 的参数。 The argument types to a lambda are not known until they are used.
lambda 的参数类型在使用之前是未知的。
You can deduce that something has an operator()
, as the other answer shows, but that's pretty much as far as it goes.您可以推断出某个东西有一个
operator()
,正如另一个答案所示,但就目前而言,这已经差不多了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.