我试图传递一个成员函数给libevent,它应该被视为回调。
#include <event.h>
class A
{
public:
void eventcb(evutil_socket_t fd, short events, void *ctx) { }
};
static void global_eventcb(evutil_socket_t fd, short events, void *ctx) { }
typedef void (A::*mthd)(evutil_socket_t, short, void*);
int main(void)
{
struct event_base *evbase = event_base_new();
mthd eventcb = &A::eventcb;
A *instance = new A;
(instance->*eventcb)(NULL, 0, NULL);
struct event *timer1 = evtimer_new(evbase, global_eventcb, NULL);
struct event *timer2 = evtimer_new(evbase, (instance->*eventcb), NULL);
return 0;
}
字符串
我可以成功地在类A中创建一个指向 eventcb 的方法指针,并在A的一个示例上调用它(第20行)。
另外,在第22行传递一个全局函数(就像在C中一样)也可以正常工作。
然而,在第23行,我试图将我的方法指针传递给 libevent,当我编译它时,我得到以下错误(使用 clang 编译器)
example.cpp:23:25: error: no matching function for call to 'event_new'
struct event *timer2 = evtimer_new(evbase, (instance->*eventcb), NULL);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from example.cpp:1:
In file included from /usr/local/include/event.h:71:
/usr/local/include/event2/event.h:749:40: note: instantiated from:
#define evtimer_new(b, cb, arg) event_new((b), -1, 0, (cb), (arg))
^~~~~~~~~
/usr/local/include/event2/event.h:833:15: note: candidate function not viable: no know conversion from '<bound member function type>' to 'event_callback_fn'
(aka 'void (*)(int, short, void *)') for 4th argument
struct event *event_new(struct event_base *, evutil_socket_t, short, event_callback_fn, void *);
^
1 error generated.
型
我做错了什么?
2条答案
按热度按时间llycmphe1#
示例方法指针需要在其上调用示例。由于libevent是一个C库,它并不直接提供一种机制来关联示例和示例方法,因此您必须自己完成这项工作。libevent的各种事件创建函数允许您将任意数据作为回调参数传递。示例指针可以通过这个参数传递,直接传递,或者如果回调函数接受额外的数据,则将其与其他参数打包在一个类中。事件回调可以是自由函数,也可以是静态方法;采取哪种方法取决于类的责任(在SOLID,单一责任的意义上)。
使用静态方法且不传递额外数据的示例:
字符串
在本例中,由于
A::handle_timeout
仅从A::invoke_timer_handler
内部调用,因此可以将其设置为私有或受保护。该示例具有非常基本的内存管理。通常,代码必须确保示例(以及其他回调参数,如果回调参数不仅仅是
A*
)在事件的生命周期内存在,以防止访问错误。它还应该确保在不再需要事件时示例不会泄漏。如果示例拥有该事件,则内存管理相对简单。并发性也会增加影响内存管理复杂性。匿名函数的现有代码级实现(例如boost::lambda)和即将到来的C++11的lambda表达式依赖于函数调用运算符(
operator()
),这在普通C中是不支持的。因此,匿名函数不适合用作libevent回调或任何其他C库回调。9udxz4iz2#
你可以使用lambda函数,只要它有一个空的捕获列表(即
[]
)。您需要将A
对象作为void*
传递,并将其强制转换回回调中的已知类型。字符串
重要的是捕获列表为空,否则lambda不能转换为函数指针。