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.
The uv_listen()
call back connector expects a static
or free (outside class) function.
Thus you should declare your function like this
static void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
_tcp* thisStream = static_cast<_tcp*>(stream);
}
Well, the static_cast<>
actually requires your _tcp
class inherits from uv_stream_t
class _tcp : public uv_stream_t {
// ...
};
To extend on your comment
"Could you please explain to me why does uv_listen expects a static function? Is this the behavior for all function pointer parameters?"
There's a difference made between class member function pointers, that need to be bound to a class instance for calling, and plain function pointers, that work for any function definition.
Why uv_listen()
expects a plain function pointer, is hard to tell. May be because it's a native C-API (I actually don't know it), or for sake of flexibility.
NOTE: You should not use leading underscores for any symbols (as in class _tcp
)!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With