将函子/lambdas与C回调一起使用

Using functors/lambdas with C callbacks

本文关键字:回调 一起 lambdas      更新时间:2023-10-16

我正在为一个流行的开源C库编写一个C++11包装器,提供RAII和您所期望的所有其他细节。包装器将仅为头(因此只需要链接到原始的C库),此外,我想坚持的原则之一是包装器应尽可能"零开销",也就是说,当启用优化时,所有内容都应内联,以便只保留C函数调用。

在大多数情况下,这并没有那么困难:正如你所期望的那样,我有一些类持有指向(不透明)C类型的指针,有调用"create"函数的构造函数、调用"destroy"功能的析构函数、调用C函数的方法等。到目前为止,很容易。

然而,我遇到的一个问题是如何处理回调。图书馆有几个形式的入口点

typedef <function signature> CallbackType;
void set_callback(CallbackType cb, void* data);

使得底层C库将cbdata存储在静态变量中,并且当发生特定事件时,触发回调,并将data与其他参数一起传递回它。

我想提供包装器,以便任何C++可调用的(即函数、函子、lambdas、使用std::bind的方法调用等)都可以在回调中使用。然而,函子和(捕获)lambdas是需要存储在某个地方的对象,以确保它们在触发回调时仍然有效。确切地把它们存放在哪里似乎有问题。。。我不能把它们放在堆上,因为它们不能被删除,而且我不能(容易地)使用静态变量,因为我的库只有头。

有人有什么建议/巧妙的想法/技巧可以在这种情况下使用吗?

提前谢谢。

致下午,如果你看到这一点:为前几天的混乱道歉,我在工作时间发布了这个关于个人项目的问题,所以我觉得最好删除它,当时它只有5次浏览,所以我认为我逃脱了惩罚,但显然不是。如果你不介意再打一次,我会对你的答案感兴趣吗

将订阅句柄和回调对象放在单个订阅包装器中。然后,用户有责任保留这个包装器,只要他想从你的c库获得回调。

class subscription
{
    std::function<void(int)> m_f;
    static void callback(int param, void* data)
    {
        static_cast<subscription*>(data)->m_f( param );
    }
    subscription( const subscription& other ) = delete;
    subscription& operator=( const subscription& ) = delete;
public:
    subscription( const std::function<void(int)>& f ) : m_f(f)
    {
        set_callback( &callback, this);
    }
    ~subscription()
    {
        clear_callback(&callback, this);
    }
};

用法:

subscription s( [](int param){ std::cout<<param*2<<std::endl; } );