2016-06-12 8 views
0

libuvにC++レイヤをラップし、コールバック関数にlambdaを使用しようとしています。しかし、gccはエラーになります。C++ラムダをC関数に渡す

ここ縮小さバージョンです:

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

が壊れていますか?この作品を作る方法は?

UPDATE:

もっと楽しい。これは、ラムダの身体に何かをします。最初の呼び出しは機能し、2番目の呼び出しは機能しません。

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

答えて

2

取り込むラムダは唯一の非キャプチャができ、関数ポインタに変換することはできません。

//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 Thanx! ..ラムダはサンクスを作りません...理解可能です。 – vrdhn

+0

@Vardhan lambda _can_は関数を変換することができますが、何もキャプチャしない場合にのみ:) – Rakete1111

+0

hmmm ..でもstd :: bind()は動作しません。 libuvが提供する 'data'フィールドを使用しなければなりません。 – vrdhn

0

たぶん、あなたは、次のいずれかのようなトリックを使用することができます。

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フィールドを使用してください。

関連する問題