2016-06-12 19 views
0

Ich versuche, eine C++ - Schicht über libuv und Lambda für Callback-Funktionen zu wickeln. Allerdings gibt es einen Fehler beim gcc.Übergabe von C++ Lambda an C-Funktionen

Hier ist die verkleinerte Version:

#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; 

Die entsprechenden Erklärungen in libuv sind:

# 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); 

Der Fehler g ++ schenkt:

$ 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)’   
})); 

Was genau ist hier gebrochen? Irgendeine Möglichkeit, dies zum Funktionieren zu bringen?

UPDATE:

Mehr Spaß .. das im Körper der Lambda etwas tut; erster Anruf funktioniert, zweiter nicht.

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

Antwort

2

Eine Erfassung Lambda kann nicht in einen Funktionszeiger umgewandelt wird, nur ein nicht-Capturing kann:

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

ok Danke! .. .. Lambda schafft keine Thunks ... verständlich. – vrdhn

+0

@Vardhan ein Lambda _can_ kann eine Funktion umgewandelt werden, aber nur wenn es nichts erfasst :) – Rakete1111

+0

hmmm .. sogar std :: bind() funktioniert nicht, versuchte mehrere Variationen; Sieht so aus, als müsste das von libuv zur Verfügung gestellte 'data'-Feld verwendet werden, um das zu stopfen. – vrdhn

0

Vielleicht können Sie einen Trick wie die folgenden verwenden:

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; 
}; 

Der Stream wird zurück gegeben, sobald etwas darauf passiert und der Griff davon ist nichts mehr als ein nackter Zeiger.
Sie können den gleichen Stream verwenden, um die Informationen des Controllers (die Instanz der Klasse Test in Ihrem Fall) zu speichern und den Stream in die ursprüngliche Form zu konvertieren, wenn Sie ihn erhalten.

Verwenden Sie andernfalls das Feld data, das Teil des Handles ist, wenn es noch nicht verwendet wird.

Verwandte Themen