包装 std::function 以忽略参数

问题描述 投票:0回答:2

我正在使用图书馆:

// External Library:
typedef void (*callback_type)(void *arg);

void external_register_callback(callback_type callback) {
    // ...
}

它允许注册回调函数:

void example_callback_function(void *arg) {
    // do something with *arg.
}

external_register_callback(example_callback_function);

我需要为库编写一个包装层,它也允许注册回调函数,但它不是带有

void*
参数的函数,而是应该采用不带参数的
std::function
。 这就是我的包装纸的样子:

void my_register_callback(std::function<void()> callback) {
    external_register_callback(... callback ...);  // how to "convert" callback to callback_type?
}

应该这样使用:

void my_callback_function() {
    // do something
}

void my_register_callback(my_callback_function);

TL;博士:

如何将我的

std::function<void()>
转换为接受
void*
参数但忽略它的函数指针?

备注:

我正在使用c++20。

函数的“转换”应该(如果可能的话)在没有运行时开销的情况下完成。需要明确的是:我不关心

register_callback()
的运行时间,但是当外部库实际调用回调时,那应该很快。

c++ c++20 std-function
2个回答
1
投票

您可以创建一个代理函数并存储它调用的

std::function<void()>
的列表。示例:

#include <functional>
#include <vector>
#include <iostream>

std::vector<std::function<void()>> proxy1_callbacks;
extern "C" // probably
void proxy1(void*) {
    for(auto&& func : proxy1_callbacks) func();
}

void my_register_callback(std::function<void()> callback) {
    proxy1_callbacks.emplace_back(std::move(callback));
    external_register_callback(proxy1);
}

演示


0
投票

当您想要将任何回调类型发送到 C 库时,有一个常见的模式。这不是删除参数,而是将您自己的回调放入上下文中。

为了简单起见,让我们想象一下我们不需要担心生命周期。

该模式包括将回调视为具有工作调用语法的对象。它可以是函数指针、lambda 或

std::function
。您将
void*
设置为指向它,然后发送一个函数指针,该指针获取上下文并将其转换回函数对象以调用它。

事情是这样的:

template<std::invocable<> F>
void my_register_callback(F& callback) {
    set_context(&callback); // sets the void*
    external_register_callback([](void* context) {
        // Retrieve the callback
        F* callback = static_cast<F*>(context);

        // Call it!
        (*callback)();
    });
}

这允许设置对 c 库的任何回调,包括函数对象、函数指针、lambda 或其他多态包装器,如

std::function

这种模式之所以有效,是因为没有捕获的 lambda 可以转换为函数指针。

© www.soinside.com 2019 - 2024. All rights reserved.