我正在使用图书馆:
// External Library:
typedef void (*callback_type)(void *arg);
void external_register_callback(callback_type callback, void* args) {
// ...
}
字符串
它允许注册回调函数:
void example_callback_function(void *arg) {
// do something with *arg.
}
external_register_callback(example_callback_function);
型
我需要为库编写一个 Package 器层,它也允许注册回调函数,但不是带有void*
参数的函数,而是应该接受不带参数的std::function
。这就是我的 Package 应该看起来像:
void my_register_callback(std::function<void()> callback) {
external_register_callback(... callback ...); // how to "convert" callback to callback_type?
}
型
它应该这样使用:
void my_callback_function() {
// do something
}
void my_register_callback(my_callback_function);
型
TL;DR:
如何将我的std::function<void()>
转换为接受void*
参数但忽略它的函数指针?
备注:
我用的是C++20
函数的“转换”应该(如果可能的话)在没有运行时开销的情况下完成。要明确的是:我不关心register_callback()
的运行时,但是当外部库实际调用回调时,应该很快。
编辑:
external_register_callback()
接受一个额外的void*
参数,该参数传递给回调函数,我将其添加到代码中。
3条答案
按热度按时间oyt4ldly1#
当你想把任何回调类型snd到c库时,有一个通用的模式。这并不是要删除参数,而是要将自己的回调放到上下文中。
为了简单起见,让我们想象一下,我们不需要担心生命周期。
该模式包括将回调作为具有工作调用语法的对象。它可以是一个函数指针,lambda或
std::function
。您设置void*
指向它,然后发送一个函数指针,该指针接受上下文并将其转换回函数对象以调用它。是这样的:
字符串
这允许设置任何对c库的回调,包括函数对象,函数指针,lambda表达式或其他多态 Package 器,如
std::function
。请记住,使用此模式,您可以完全跳过
std::function
可能发生的双重间接。这种模式之所以有效,是因为没有捕获的lambda表达式可以转换为函数指针。
额外的好处是,您也不依赖于全局对象来使该调用与C库一起工作。
现在,对于生存期,我想说,你绝对可以在你的 Package 器层中管理函数对象的生存期,并根据你的需要保持它的生存期,最好直到你取消回调。
7gcisfzg2#
您可以创建一个代理函数并存储它调用的
std::function<void()>
的列表。范例:字符串
Demo
如果
external_register_callback
实际上也接受void*
参数型
然后在调用时提供给回调函数(这很常见),您可以使用该
void*
指向您的std::function<void()>
。型
Demo的
除了使用单独的
my_register_callback
函数之外,还可以让类注册到C风格的回调框架中,以便在已注册的对象上调用特定的事件处理程序。假设你有几个不同的C风格的注册函数用于你正在使用的API:
型
然后可以创建注册
static
成员函数的类的示例。在这些函数中,您将强制转换回class
类型并调用(非static
)目标成员函数。型
Demo的
如果你希望不同的类能够注册,你可以使用多态性。您可以通过使
on_x
/on_y
成为virtual
来使用运行时多态性,也可以在编译时使用CRTP来实现。下面是一个CRTP示例:的字符串
Demo的
f45qwnt83#
如果你可以控制函数接收到的
void*
,你应该让它指向你想要调用的std::function<void()>
示例,然后在你的自定义回调中调用它:字符串
否则,您需要一个全局示例,您的回调可以从其中调度:
型