是否可以包装 C 风格的回调,以便您可以将 C++ lambda 与它们一起使用?
Is it possible to wrap C-style callbacks so that you can use C++ lambdas with them?
我处于一个不幸的位置,一些 C++ 代码需要与用 C 编写的外部库通信。具体来说,Enlightenment 套件,除其他地方外,还用于处理某些 GUI智能手表。
例如,让我们以函数ecore_timer_add()
:
为例
EAPI Ecore_Timer * ecore_timer_add (double interval, Eina_Bool(*function)(void *), const void *data)
调用时,这将在 interval
秒后调用 function()
,将 data
作为单个参数传递给它。
在 C 中,这是获得通用函数回调的唯一方法,因为没有函数重载和模板。但是,在 C++ 中,我们通常使用 lambda,或者可能使用 std::function
之类的工具来处理回调。
但是我们如何混合使用这些技术呢?
捕获 lambda 不能转换为函数指针(这是有道理的,因为它们必须以某种方式传递其内部捕获的状态)。
但是,也许可以创建一个不捕获的 'wrapper' 函数,它接收打包在其 void * data
参数中的 lambda,然后能够调用它?
我试过写这个,但到目前为止还没有成功。
可能需要一些高级模板技巧才能让编译器弄清楚如何将 lambda to/from 转换为 void *
.
只需添加另一层间接寻址:
auto f = [=]() { /* ... */ };
ecore_timer_add(interval, [](void *data) { return (*reinterpret_cast<decltype(f)*>(data))(); }, &f);
注意这里的生命周期问题(可能想将捕获的 lambda f
填充到 std::function
中并将其存储在某个容器中,以便您可以维护指向它的有效指针)。
我处于一个不幸的位置,一些 C++ 代码需要与用 C 编写的外部库通信。具体来说,Enlightenment 套件,除其他地方外,还用于处理某些 GUI智能手表。
例如,让我们以函数ecore_timer_add()
:
EAPI Ecore_Timer * ecore_timer_add (double interval, Eina_Bool(*function)(void *), const void *data)
调用时,这将在 interval
秒后调用 function()
,将 data
作为单个参数传递给它。
在 C 中,这是获得通用函数回调的唯一方法,因为没有函数重载和模板。但是,在 C++ 中,我们通常使用 lambda,或者可能使用 std::function
之类的工具来处理回调。
但是我们如何混合使用这些技术呢?
捕获 lambda 不能转换为函数指针(这是有道理的,因为它们必须以某种方式传递其内部捕获的状态)。
但是,也许可以创建一个不捕获的 'wrapper' 函数,它接收打包在其 void * data
参数中的 lambda,然后能够调用它?
我试过写这个,但到目前为止还没有成功。
可能需要一些高级模板技巧才能让编译器弄清楚如何将 lambda to/from 转换为 void *
.
只需添加另一层间接寻址:
auto f = [=]() { /* ... */ };
ecore_timer_add(interval, [](void *data) { return (*reinterpret_cast<decltype(f)*>(data))(); }, &f);
注意这里的生命周期问题(可能想将捕获的 lambda f
填充到 std::function
中并将其存储在某个容器中,以便您可以维护指向它的有效指针)。