何时使用函数模板而不是通用 lambda?

Posted

技术标签:

【中文标题】何时使用函数模板而不是通用 lambda?【英文标题】:When use a function template instead of a generic lambda? 【发布时间】:2014-05-17 13:20:39 【问题描述】:

我可以写一个函数模板:

template<typename T>
void f1(T parameter)  ... 

但在 C++14 中,我也可以创建一个通用 lambda:

auto f2 = [](auto parameter)  ... ;

f1内可以直接参考T。在f2 中,没有T 可以引用,但我可以使用decltype 获得相同的效果:

auto f2 = [](auto parameter)
          
            using T = decltype(param);
            ...
          ;

通用 lambda 的一个优点是我可以完美地转发它。我不能用函数模板做到这一点:

template<typename T>
void fwdToG(T&& param)  g(std::forward<T>(param)); 

fwdToG(f1);        // error!
fwdToG(f2);        // okay

在某些情况下使用函数模板会比使用通用 lambda 更好吗?

【问题讨论】:

等等,你不能?为什么一个是通用参考而另一个不是?错误是什么?这会给您带来什么问题?什么是g g 是我想调用的其他函数; fwdToG 是完美转发功能。错误是 f1 没有类型(它是模板,不是函数),因此尝试将其传递给 fwdToG 失败。 啊,是的,好的。那么这不是回答你的问题吗? 我展示的是通用 lambda 优于函数模板的优势。我在问函数模板是否比通用 lambda 有优势。 很公平。对于它的价值,我想不出任何东西。 【参考方案1】:

函数templates 允许重载具有相同名称的其他函数,并通过ADL 调用它们。通用 lambda 是具有重载 () 的对象,因此两者都不起作用。

您可以很容易地将函数重载集传递给对象:

 struct foo_overload_set_t 
   template<class...Ts>
   constexpr auto operator()(Ts&&...ts)const return foo(std::forward<Ts>(ts)...); 
 ;

使用 RVO 可以完全优化(零开销),并且可以将整个重载集的实例传递给算法。您也可以在使用点使用 lambda 来执行此操作,它可以由宏生成。

通过更多样板,上述重载集还可以支持转换为任何调用兼容的函数指针,template 和 lambda 解决方案都不支持(lambda 要求签名匹配一个版本,不兼容)。

【讨论】:

你能举个例子说明你给函数传递一个重载集是什么意思吗? @knowitallwannabe std::sort(it1,it2,foo_overload_set_t) 将进行重载查找并在std::sort 内调用foo。基本上,您可以将查找正确的重载包装到可以传递的对象中。 @knowitallwannabe 请注意,我没有足够强调这两个优点:重载(在class 之外,如此分布)和 ADL(在命名空间之外如此重载!)它们两个让您编写代码靠近它应该在的地方,而不是语言规定的地方。 我认为重载和 ADL 功能在您的回答中很明显,我对此表示赞同。 这是否意味着通常应该首选函数模板?或者是否存在明显的情况,泛型 Lamba 更好(作为直接函数参数除外)?

以上是关于何时使用函数模板而不是通用 lambda?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 std::apply 可以调用 lambda 而不是等效的模板函数?

带有模板参数的 Lambda 函数,而不是函数参数

将模板函数转换为通用 lambda

lambda 是不是应该衰减为模板代码中的函数指针?

模板方法何时可以使用稍后定义的函数,而无需前向声明?

通用 lambda 的熟悉模板语法