简体   繁体   English

在模板中匹配 C++ lambda 表达式

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM