如何声明一个接受lambda表达式的函数?

99

我在网络上阅读了许多教程,它们解释了如何使用标准库(例如std::find)与Lambda表达式。这些教程非常有趣,但我找不到任何一个解释如何为自己的函数使用Lambda表达式。

例如:

int main()
{
    int test = 5;
    LambdaTest([&](int a) { test += a; });

    return EXIT_SUCCESS;
}

我应该如何声明 LambdaTest?它的第一个参数的类型是什么?然后,我该如何调用传递给它的匿名函数 - 例如 - 将 "10" 作为其参数传递给它?

3个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
91

如果您不想将所有内容都进行模板化,可以采取以下方法:

#include<functional> 

void LambdaTest (const std::function <void (int)>& f)
{
    ...
}

1
这个语法实际上允许我保存函数变量以便稍后调用,对吗?例如,我想要实现一个函数,允许执行异步数据库查询,其中 lambda 充当回调函数。(当然,我无法通过引用访问闭包) - Andreas Bonini
3
将函数按值传递不是更符合惯用法吗? - fredoverflow
5
@Andreas Bonini:是的,如果你保存到std::function(不是引用),你会复制f。然而,我不确定lambda/闭包在所引用的对象超出作用域时如何处理引用,可能是未定义行为。 @FredOverflow:我的理解是,特别是在包装lambda时,std::function不是一个简单的对象。最好引用它以避免不必要的复制。 - user319799
1
如果您的lambda通过值捕获堆栈,则lambda可以超出这些变量的生命周期,并将继续保留它们的副本。如果它通过引用捕获,那么您将会遇到问题。 - Kate Gregory
1
我们需要将它复制到函数内部,因此没有必要在传递时复制它。 - Casebash

86

考虑到您可能还想接受函数指针和函数对象,除了lambda表达式以外,您可能需要使用模板来接受具有operator()的任何参数。这就是像find这样的std-functions所做的事情。代码如下:

template<typename Func>
void LambdaTest(Func f) {
    f(10);
}

请注意,此定义不使用任何C++0x功能,因此它是完全向后兼容的。只有使用lambda表达式调用函数是C++0x特定的。


5
如果出现错误,错误信息可能会难以理解。 - liori
15
这取决于它是否是最佳选择。这个使用了模板,另一个没有。这意味着该函数不能再是虚函数,也不能在cpp文件中单独定义。std::function 完全能够接受函数对象类类型,尽管调用时速度稍慢。但对于大多数应用程序来说,这种差异是可以忽略不计的 :) - Johannes Schaub - litb
4
“最好的”在观察者眼中。这个答案使用了一个“函数对象”,很不错,但并没有真正回答最初的问题(也是我来到这里的原因),即“如何为自己的函数使用lambda表达式”。此外,模板有其自己的一套问题,而使用“std::function”的答案则没有这些问题。 - Marco Massenzio
2
@Marco 这个答案不要求你使用函数,它允许你使用任何你想用的东西 - 包括 lambda。 - sepp2k
谁在强制要求函数的参数为int类型?有时候过于泛化会导致错误。 - Luca Venturini

10

我想贡献这个简单而自说明的例子。它展示了如何将“可调用的东西”(函数、函数对象和Lambda表达式)传递给函数或对象。

// g++ -std=c++11 thisFile.cpp

#include <iostream>
#include <thread>

using namespace std;

// -----------------------------------------------------------------
class Box {
public:
  function<void(string)> theFunction; 
  bool funValid;

  Box () : funValid (false) { }

  void setFun (function<void(string)> f) {
    theFunction = f;
    funValid = true;
  }

  void callIt () {
    if ( ! funValid ) return;
    theFunction (" hello from Box ");
  }
}; // class

// -----------------------------------------------------------------
class FunClass {
public:
  string msg;
  FunClass (string m) :  msg (m) { }
  void operator() (string s) {
    cout << msg <<  s << endl; 
  }
};

// -----------------------------------------------------------------
void f (string s) {
  cout << s << endl;
} // ()

// -----------------------------------------------------------------
void call_it ( void (*pf) (string) ) {
  pf( "call_it: hello");
} // ()

// -----------------------------------------------------------------
void call_it1 ( function<void(string)> pf ) {
  pf( "call_it1: hello");
} // ()

// -----------------------------------------------------------------
int main() {

  int a = 1234;

  FunClass fc ( " christmas ");

  f("hello");

  call_it ( f );

  call_it1 ( f );

  // conversion ERROR: call_it ( [&] (string s) -> void { cout << s << a << endl; } );

  call_it1 ( [&] (string s) -> void { cout << s << a << endl; } );

  Box ca;

  ca.callIt ();

  ca.setFun (f);

  ca.callIt ();

  ca.setFun ( [&] (string s) -> void { cout << s << a << endl; } );

  ca.callIt ();

  ca.setFun (fc);

  ca.callIt ();

} // ()

3
不需要funValid:http://en.cppreference.com/w/cpp/utility/functional/function/operator_bool,只需写`if ( ! theFunction )`。请注意,在翻译过程中不会提供解释或额外的内容。 - Erik Aronesty

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,