模板化函数是应该按值还是通过右值引用获取lambda参数?

时间:2012-09-22 23:52:18

标签: c++ templates lambda c++11 g++

C ++ 11模式下的GCC 4.7让我定义一个以两种不同方式处理lambda的函数:

// by value
template<class FunctorT>
void foo(FunctorT f) { /* stuff */ }

// by r-value reference
template<class FunctorT>
void foo(FunctorT&& f) { /* stuff */ }

但不是:

// by reference
template<class FunctorT>
void foo(FunctorT& f) { /* stuff */ }

我知道我可以取消模板函数,只需要使用std :: functions,但是foo很小而且内联,我想给编译器提供内联调用f的最佳机会。它在里面。在前两个中,如果我特别知道我正在传递lambdas,那么这对于性能更可取,为什么不允许将lambda传递给最后一个?

2 个答案:

答案 0 :(得分:30)

FunctorT&&通用引用,可以匹配任何内容,而不仅仅是rvalues。它是在C ++ 11模板中传递内容的首选方式,除非您绝对需要副本,因为它允许您使用完美转发。通过std::forward<FunctorT>(f)访问该值,如果之前是f,则会使std::forward再次成为左值,否则会将其保留为左值。阅读有关转发问题的更多herestd::forward,并阅读here,了解FunctorT&如何真正有效的分步指南。 This也是一本有趣的读物。

{{1}}只是一个简单的左值引用,你不能将临时值(lambda表达式的结果)绑定到该值。

答案 1 :(得分:3)

这是一个很好的问题 - 第一部分:按值传递或使用转发。我认为第二部分(以FunctorT&为参数)得到了合理的回答。

我的建议是:只有在事先知道函数对象时才使用转发来修改其闭包(或捕获列表)中的值。最好的例子:std :: shuffle。它需要一个统一随机数生成器(一个函数对象),每次调用生成器都会修改它的状态。函数对象被转发到算法中。

在所有其他情况下,您应该更愿意传递价值。这不会阻止您通过引用捕获本地并在lambda函数中修改它们。这将像你认为的那样工作。 Dietmar说,复制应该没有开销。内联也将适用,并且可以优化参考。