c++ - 是否可以包装 C 风格的回调,以便您可以将 C++ lambda 与它们一起使用?

标签 c++ lambda closures c++14 function-pointers

我处于一些 C++ 代码需要与用 C 编写的外部库通信的不幸位置。具体来说,Enlightenment套件,除其他地方外,还用于处理某些智能 watch 上的 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 不能转换为函数指针(这是有道理的,因为它们必须以某种方式传递其内部捕获的状态)。

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

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

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

最佳答案

只需添加另一层间接:

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

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

关于c++ - 是否可以包装 C 风格的回调,以便您可以将 C++ lambda 与它们一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68522609/

相关文章:

c++ - 编译 DeSiGn 时出错

像 __TIME__ 这样的 C++ 预处理器指令有时不会改变/不会更新

C++ 和 Sqlite DELETE 查询实际上并没有从数据库文件中删除值

python - Lambda 表达式替换

swift - 我的关闭有什么问题?

c++ - OpenGL使用统一缓冲区作为数组

c# - 如何为此创建扩展方法/lambda 函数

c++ - 使用参数将只能移动的对象捕获到 lambda

javascript - 是否可以像在 Javascript 中那样在 AS2 中使用闭包?

swift - 将可变参数闭包参数标记为转义