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


82

我在互联网上阅读了许多教程,这些教程解释了如何在标准库(例如std::find)中使用lambda ,它们都很有趣,但是我找不到任何可以解释如何将lambda用于自己的函数的教程。

例如:

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

    return EXIT_SUCCESS;
}

我该如何申报LambdaTest?它的第一个参数是什么类型?然后,如何调用传递给它的匿名函数-例如,以“ 10”作为参数?

Answers:


78

鉴于除了lambda之外,您可能还希望接受函数指针和函数对象,因此您可能希望使用模板来接受带operator()。这就是像find一样的std函数。它看起来像这样:

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

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


2
如果出现错误,错误消息将很难理解。
liori 2010年

13
这取决于它是否是最好的。这使用一个模板,而另一个不使用。这意味着该函数不再是虚拟的,并且不能在cpp文件中单独定义。std::function完全能够接受函数对象类类型,尽管调用时速度稍慢。但是对于大多数应用而言,这种差异可以忽略不计:)
Johannes Schaub-litb 2010年

2
“最好”在旁观者的眼中:-)这个答案使用了一个functor不错的a,但是并没有真正回答最初的问题(以及导致我在这里出现的问题)的原始问题,即“我如何使用lambda来实现自己的功能” 。此外,模板也有自己的问题集,而答案std::function却没有。
Marco Massenzio

1
@Marco此答案不需要您使用函子,它使您可以使用任何想要的东西-包括lambda。
sepp2k

68

如果您不想为所有内容建立模板,则可以执行以下操作:

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

1
实际上,这种语法使我可以保存函数变量以供以后调用,对吗?例如,我想实现一个允许执行异步数据库查询的功能,其中lambda充当回调。(当然,我不能通过引用来访问闭包)
Thomas Bonini,2010年

1
按值传递函数不是更习惯吗?
fredoverflow

1
@Andreas Bonini:是的,如果保存到std::function(而不是引用),请复制f。但是,我不确定当引用的对象超出范围(可能是UB)时,lambda / closures如何处理引用。@FredOverflow:我的理解是,这std::function不是一个琐碎的对象,尤其是在包装lambda时。最好参考它以避免不必要的复制。
2010年

如果您的lambda通过值捕获堆栈,则可以,lambda可以使这些变量失效,并将继续保留它们的副本。如果它通过引用捕获,您将遇到问题。
凯特·格雷戈里

1
我们将不得不在函数内部复制它,因此在传递它时复制它毫无意义
Casebash 2011年

9

我想贡献这个简单但不言自明的例子。它显示了如何将“可调用事物”(函数,函数对象和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 ();

} // ()

2
您不需要funValid:en.cppreference.com/w/cpp/utility/functional/function / ...,只需说if ( ! theFunction )
Erik Aronesty
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.