【问题标题】:How to declare a function that accepts a lambda?如何声明一个接受 lambda 的函数?
【发布时间】:2011-02-25 16:25:20
【问题描述】:

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

例如:

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

    return EXIT_SUCCESS;
}

我应该如何声明LambdaTest?它的第一个参数的类型是什么?然后,我怎样才能调用传递给它的匿名函数——例如——“10”作为它的参数?

【问题讨论】:

    标签: c++ lambda c++11


    【解决方案1】:

    考虑到除了 lambda 之外,您可能还希望接受函数指针和函数对象,您可能希望使用模板来接受带有 operator() 的任何参数。这就是像 find 这样的标准函数。它看起来像这样:

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

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

    【讨论】:

    • 如果出现错误,错误消息将难以理解。
    • 这取决于它是否是最好的。这使用了一个模板,而另一个没有。这意味着该函数不能再是虚拟的,也不能在 cpp 文件中单独定义。 std::function 也完全能够采用函数对象类类型,尽管调用时会慢一些。但是对于大多数应用程序来说,这种差异可以忽略不计:)
    • "best" 在旁观者的眼中 :-) 这个答案使用了 functor,这很好,但并没有真正回答原来的问题(以及是什么导致我来到这里),即“我如何将 lambda 用于我自己的函数”。此外,模板有自己的一组问题,std::function 的答案没有。
    • @Marco 这个答案不需要你使用函数,它允许你使用任何你想要的东西——包括 lambdas。
    【解决方案2】:

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

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

    【讨论】:

    • 这个语法其实可以让我保存函数变量以便以后调用,对吧?例如,我想实现一个允许执行异步数据库查询的函数,其中 lambda 充当回调。 (当然我不能通过引用访问闭包)
    • 按值传递函数不是更惯用吗?
    • @Andreas Bonini:是的,如果你保存到std::function(不是参考),你就复制了f。但是,我不确定当引用的对象超出范围(可能是 UB)时 lambda/closures 如何处理引用。 @FredOverflow:我的理解是 std::function 不是一个微不足道的对象,尤其是在包装 lambda 时。最好引用它以避免不必要的复制。
    • 如果您的 lambda 按值捕获堆栈,那么是的,lambda 可以比这些变量寿命更长,并将继续保留它们的副本。如果它通过引用捕获,您将遇到问题。
    • 我们必须在函数内部复制它,所以没有必要复制它,因为它是传入的
    【解决方案3】:

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

    // 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 ();
    
    } // ()
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-30
    • 2012-07-11
    • 2018-11-17
    • 1970-01-01
    • 1970-01-01
    • 2018-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多