我应该通过const引用传递lambda.

jwh*_*els 13 c++ lambda closures pass-by-reference c++11

通常我在接受lambda作为函数的参数时使用以下模式(模板类传递值):

template <class Function>
void higherOrderFunction(Function f) {
     f();
}
Run Code Online (Sandbox Code Playgroud)

这是否复制(关闭)参数?如果是这样,通过const引用接受lambda有什么不对吗?

template <class Function>
void higherOrderFunction(const Function& f) {
  f();
}
Run Code Online (Sandbox Code Playgroud)

一个简单的测试似乎表明这种方法很好,但我想知道是否有任何特殊的考虑因素我应该注意.

Pra*_*ian 15

如果你传递值,你将复制闭包对象(假设你没有定义lambda内联,在这种情况下它将被移动).如果复制状态昂贵,则可能不合需要,如果状态不可复制,则无法编译.

template <class Function>
void higherOrderFunction(Function f);

std::unique_ptr<int> p;
auto l = [p = std::move(p)] {}; // C++14 lambda with init capture
higherOrderFunction(l);         // doesn't compile because l is non-copyable 
                                // due to unique_ptr member
higherOrderFunction([p = std::move(p)] {}); // this still works, the closure object is moved
Run Code Online (Sandbox Code Playgroud)

如果通过const引用传递,则无法传递mutable将其数据成员修改为参数higherOrderFunction()mutablelambda ,因为lambda具有非const operator(),并且您无法在const对象上调用它.

template <class Function>
void higherOrderFunction(Function const& f);

int i = 0;
higherOrderFunction([=]() mutable { i = 0; }); // will not compile
Run Code Online (Sandbox Code Playgroud)

最好的选择是使用转发参考.然后higherOrderFunction可以接受调用者传递的左值或右值.

template <class Function>
void higherOrderFunction(Function&& f) {
     std::forward<Function>(f)();
}
Run Code Online (Sandbox Code Playgroud)

这允许简单的情况以及上面提到的情况进行编译.有关std::forward应该使用的原因的讨论,请参阅此答案.

现场演示

  • 公平地说,使用`std`算法按值获取函数,人们应该知道如果他们有一个有限寿命的高成本函数对象,他们应该`std :: ref`它. (5认同)
  • @ChrisGuzak我在最后链接到[另一个答案](/sf/answers/2187757981/),解释了为什么使用`std::forward`可以产生影响。 (2认同)