将 c++ lambda 传递给 C 函数

Passing c++ lambda to C functions

本文关键字:函数 c++ lambda      更新时间:2023-10-16

我正在尝试在libuv上包装一个C++层,并将lambda用于回调函数。然而,gcc 出错了。

这是缩小版本:

#include <uv.h>
class Test {
public:
  void on_conn(uv_stream_t *server, int status) {   }
  void test() {
    uv_tcp_t server;
    auto err = uv_listen((uv_stream_t*)&server,
             100,
             [this]  (uv_stream_s *server, int status) -> void {
               this->on_conn(server,status);
             });
  }
};
Test t;

libuv中的相关声明是:

#   define UV_EXTERN /* nothing */
struct uv_stream_s { ... };
typedef struct uv_stream_s uv_stream_t;
typedef void (*uv_connection_cb)(uv_stream_t* server, int status);
UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);

错误 g++ 给出:

$ g++ --version
g++ (GCC) 6.1.1 20160501
<<--ERROR--{reformatted}-->>
t.cpp:15:7: error: cannot convert 
         ‘Test::test()::<lambda(uv_stream_s*, int)>’ to 
‘uv_connection_cb {aka void (*)(uv_stream_s*, int)}’ 
 for argument ‘3’ to ‘int uv_listen(uv_stream_t*, int, uv_connection_cb)’        
 }));

这里到底坏了什么?有什么方法可以做到这一点吗?

更新:

更有趣.. 这在 lambda 的主体中做了一些事情 ; 第一次调用有效,第二次调用无效。

int cfunc( void cb() );
class Test {
public:
  void d(){}
  void test() {
    cfunc( [=]  () {});
    cfunc( [=]  () { this->d(); });
    //cfunc( [this]  () { });
    //cfunc( [&this]  () { });
  }
};
t.cpp:10:34: error: cannot convert ‘Test::test()::<lambda()>’ to ‘void (*)()’ for argument ‘1’ to ‘int cfunc(void (*)())’
 cfunc( [=]  () { this->d(); });

捕获 lambda 不能转换为函数指针,只有非捕获可以:

//Lambda captures 'this', and so cannot be converted to function pointer
[this](uv_stream_s *server, int status) -> void {
       this->on_conn(server,status);
    }

也许您可以使用如下所示的技巧:

class Test;
struct my_uv_tcp_t: uv_tcp_t {
    Test *test;
};
class Test {
public:
    Test(): server{} { server.test = this; }
    void on_conn(uv_stream_t *server, int status) {   }
    static void cb(uv_stream_t *server, int status) {
        auto srv = static_cast<my_uv_tcp_t*>(server);
        srv->test->on_conn(server, status);
    }
    void test() {
        auto err = uv_listen((uv_stream_t*)&server, 100, Test::cb);
    }
private:
    my_uv_tcp_t server;
};

一旦流上发生某些事情,它就会被返回,它的句柄只不过是一个裸指针。
您可以使用同一流来存储控制器(在本例中为 Test 类的实例)的信息,并在收到流时将其转换为其原始形式。

否则,如果 data 字段仍未使用,请使用作为句柄一部分

的字段。

它应该是工作。我遇到了同样的问题,所以我通过句柄对象属性将当前对象发送到 lambda。

   #include <uv.h>
    class Test {
    public:
      void on_conn(uv_stream_t *server, int status) {   }
      void test() {
        uv_tcp_t server;
        server.data = this;
        auto err = uv_listen((uv_stream_t*)&server,
                 100,
                 []  (uv_stream_s *server, int status) -> void {
                    auto self = (Test*)server->data;
                   self->on_conn(server,status);
                 });
      }
    };
    Test t;