首页 > 解决方案 > 将 lambdas 作为回调传递给 C 函数

问题描述

假设我有一个 C 函数

typedef void (* callback_t)(void* data);
status_you_dont_care_about register_callback(callback_t callback, void* data);

我想传递一个 lambda 作为回调。

这样做的惯用方法是什么...

  1. 当 lambda 什么都没有捕获?
  2. 当 lambda 有捕获(按值、按引用等)?

标签: c++c++11lambdacallbackidioms

解决方案


非捕获案例

正如评论者指出的那样,lambda 隐式转换为适当类型的函数指针,所以我们可以写:

auto my_lambda = [](void* data) { /* do stuff here */};
register_callback(my_lambda, get_pointer_to_data());

这将编译。不过不要忘记检查返回值:-)

抓包案例

这就是我目前正在做的事情,但我怀疑它不是最理想的。

首先,我确保 lambda 捕获它需要的所有内容,以便它本身可以在没有参数的情况下调用(因此它实际上不需要void*回调应该的那样)。然后我使用这段代码:

template <typename Invokable>
void callback_adapter(void *invokable_on_heap)
{
    auto retyped_callback = std::unique_ptr<Invokable>{
        reinterpret_cast<Invokable*>(invokable_on_heap)
     };
    (*retyped_callback)(std::forward<Ts>(parameters)...);
    // Note: invokable_on_heap will be delete'd
}

template <typename Invokable>
void register_invokable_as_callback(Invokable callback_) {
    Invokable* invokable_on_the_heap = new Invokable(std::move(callback_));
    register_callback(&callback_adapter<Invokable>, invokable_on_the_heap);
}

注意:使用这种方法,回调只能被调用一次。它可以适应需要多次调用的回调的情况,在取消注册/销毁任何调用回调时解除分配。


推荐阅读