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

Matching a C++ lambda expression in templates

本文关键字:c++ lambda 表达式      更新时间:2023-10-16

我正在尝试匹配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()定义。这个问题很容易用表达式约束来解决。但是,由于没有接收参数,因此很难检查表达式是否有效。

这不是一个通用的例子,但它将适用于任何没有将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(),正如另一个答案所示,但这几乎就是它的极限了。