I'm trying to create a class to abstract some basic behavior of libuv's networking functions.
#define TCP_BACKLOG 256
class _tcp {
uv_tcp_t* tcp = NULL;
public:
~_tcp() { delete tcp; }
void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
}
void listen(const char* host, int port) {
tcp = new uv_tcp_t();
uv_tcp_init(uv_default_loop(), tcp);
sockaddr_in* addr = new sockaddr_in();
uv_ip4_addr(host, port, addr);
uv_tcp_bind(tcp, (const sockaddr*)addr, 0);
delete addr;
uv_listen((uv_stream_t*)tcp, TCP_BACKLOG, listen_uv_listen_uv_connection_cb);
}
};
The problem with the previously shown code is that when I try to compile it I get the following error:
error: reference to non-static member function must be called
on: uv_listen((uv_stream_t*)tcp, TCP_BACKLOG, listen_uv_listen_uv_connection_cb);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
And it points to listen_uv_listen_uv_connection_cb
as the culprit.
Can someone explain to me, why is that an error, and how am I supposed to fix it?
The uv_listen()
and uv_connection_cb
signatures are declared as follows
UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
typedef void (*uv_connection_cb)(uv_stream_t* server, int status);
You cannot convert non-static member function to a pointer to function even with the same signature, as technically member function has a hidden parameter called this
. One of the solution is to make listen_uv_listen_uv_connection_cb
static:
class _tcp {
uv_tcp_t* tcp = NULL;
public:
~_tcp() { delete tcp; }
static void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
}
void listen(const char* host, int port) {
tcp = new uv_tcp_t();
uv_tcp_init(uv_default_loop(), tcp);
sockaddr_in* addr = new sockaddr_in();
uv_ip4_addr(host, port, addr);
uv_tcp_bind(tcp, (const sockaddr*)addr, 0);
delete addr;
uv_listen((uv_stream_t*)tcp, TCP_BACKLOG,
&_tcp::listen_uv_listen_uv_connection_cb);
}
};
PS to be able to call a non-static method you would need a way to get a pointer to your _tcp
instance from "uv_stream_t* stream" parameter. I would suggest to use "void* uv_handle_t.data" pointer from this doc http://docs.libuv.org/en/latest/handle.html#c.uv_handle_t
static void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
_tcp *tcp = static_cast<_tcp *>( stream->data );
tcp->regularMethod();
}
Of course you should assign this
pointer to uv_handle_t.data
when you initialize uv_tcp_t *
:
void listen(const char* host, int port) {
tcp = new uv_tcp_t();
uv_tcp_init(uv_default_loop(), tcp);
tcp->data = this; // do not forget it
...
}
and I would move this initialization code to constructor.
You would need such static wrapper for every callback you are going to use with this library. With c++11 you probably can use lambda instead.