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

Is it possible to wrap C-style callbacks so that you can use C++ lambdas with them?

提问人:Qqwy 提问时间:7/26/2021 最后编辑:Remy LebeauQqwy 更新时间:7/26/2021 访问量:102

问:

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

举个例子,让我们以函数 ecore_timer_add()

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

调用时,这将在几秒钟后调用,并作为单个参数传递给它。function()intervaldata

在 C 语言中,这是获得泛型函数回调的唯一方法,因为没有函数重载,也没有模板。但是,在 C++ 中,我们通常使用 lambda,或者可能使用诸如处理回调之类的工具。std::function

但是我们如何才能混合这些技术呢?

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

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

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

它可能需要一些高级模板技巧,以允许编译器弄清楚如何将 lambda 强制转换为/从 .void *

C++ Lambda 闭包 C++14 函数指针

评论


答:

7赞 Kyle 7/26/2021 #1

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

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

这里要警惕生存期问题(可能希望将捕获的 lambda 塞入 a 中,并将其存储在某个容器中,以便您可以维护指向它的有效指针)。fstd::function