Я пытаюсь создать класс, чтобы абстрагироваться от базового поведения сетевых функций libuv.
#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);
}
};
Проблема с ранее показанным кодом заключается в том, что когда я пытаюсь скомпилировать его, я получаю следующую ошибку:
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);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
И это указывает на listen_uv_listen_uv_connection_cb
как виновник.
Может кто-нибудь объяснить мне, почему это ошибка, и как я должен это исправить?
uv_listen()
а также uv_connection_cb
подписи объявляются следующим образом
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);
Вы не можете преобразовать нестатическую функцию-член в указатель на функцию даже с той же сигнатурой, поскольку технически функция-член имеет скрытый параметр, называемый this
, Одним из решений является сделать listen_uv_listen_uv_connection_cb
статическая:
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, чтобы иметь возможность вызывать нестатический метод, вам нужен способ получить указатель на ваш _tcp
Экземпляр из параметра «uv_stream_t * stream». Я бы предложил использовать указатель «void * uv_handle_t.data» из этого документа 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();
}
Конечно, вы должны назначить this
указатель на uv_handle_t.data
когда вы инициализируете 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
...
}
и я бы переместить этот код инициализации в конструктор.
Вам понадобится такая статическая оболочка для каждого обратного вызова, который вы собираетесь использовать с этой библиотекой. С c ++ 11 вы, вероятно, можете вместо этого использовать лямбду.
uv_listen()
соединитель обратного вызова ожидает static
или свободная (вне класса) функция.
Таким образом, вы должны объявить свою функцию следующим образом
static void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
_tcp* thisStream = static_cast<_tcp*>(stream);
}
Ну, то static_cast<>
на самом деле требует вашего _tcp
класс наследует от uv_stream_t
class _tcp : public uv_stream_t {
// ...
};
Продлить на ваш комментарий
«Не могли бы вы объяснить мне, почему uv_listen ожидает статическую функцию? Это поведение для всех параметров указателя функции?»
Существует различие между указателями на функции-члены класса, которые должны быть связаны с экземпляром класса для вызова, и обычными указателями на функции, которые работают для любого определения функции.
Зачем uv_listen()
ожидает простой указатель на функцию, сказать сложно. Может быть потому, что это родной C-API (на самом деле я этого не знаю) или ради гибкости.
НОТА: Вы не должны использовать начальные подчеркивания для любых символов (как в class _tcp
)!
void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
}; <<<<<remove ;
В конце определения функции не должно быть точки с запятой.
И вы должны написать конструктор / копировать оператор ctr / assign для этого класса.