libuv — ошибка C ++: должна быть вызвана ссылка на нестатическую функцию-член

Я пытаюсь создать класс, чтобы абстрагироваться от базового поведения сетевых функций 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);

5

Решение

Вы не можете преобразовать нестатическую функцию-член в указатель на функцию даже с той же сигнатурой, поскольку технически функция-член имеет скрытый параметр, называемый 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 вы, вероятно, можете вместо этого использовать лямбду.

8

Другие решения

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)!

1

void listen_uv_listen_uv_connection_cb(uv_stream_t* stream, int status) {
printf("NEW CONNECTION\n");
};        <<<<<remove ;

В конце определения функции не должно быть точки с запятой.

И вы должны написать конструктор / копировать оператор ctr / assign для этого класса.

0
По вопросам рекламы [email protected]