是否可以包装 C 样式的回调,以便您可以将 C++ lambdas 与它们一起使用?

问题描述

不幸的是,某些 C++ 代码需要与用 C 编写的外部库进行通信。具体来说,Enlightenment 套件用于处理某些智能手表上的 GUI .

函数ecore_timer_add()为例:

EAPI Ecore_Timer * ecore_timer_add  (double interval,Eina_Bool(*function)(void *),const void *data)

调用时,这将在 function() 秒后调用 interval,将 data 作为单个参数传递给它。

在 C 中,这是具有通用函数回调的唯一方法,因为没有函数重载和模板。但是,在 C++ 中,我们通常使用 lambda 表达式,或者可能使用 std::function 之类的工具来处理回调。

但是我们如何混合使用这些技术?

捕获 lambda 不能转换为函数指针(这是有道理的,因为它们必须以某种方式传递内部捕获的状态)。

但是,也许可以创建一个不捕获的“包装器”函数,它接收打包在其 void * data 参数中的 lambda,然后能够调用它?

我尝试过写这个,但到目前为止还没有成功。

它可能需要一些高级模板技巧才能让编译器弄清楚如何将 lambda 转换为 void *

解决方法

只需添加另一个间接级别:

auto f = [=]() { /* ... */ };
ecore_timer_add(interval,[](void *data) { return (*reinterpret_cast<decltype(f)*>(data))(); },&f);

注意这里的生命周期问题(可能想要将捕获的 lambda f 填充到 std::function 中并将其存储在某个容器中的某个位置,以便您可以维护指向它的有效指针)。