使用带有C回调的functor / lambdas

时间:2014-08-26 16:47:17

标签: c++ c++11 lambda callback wrapper

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

在大多数情况下,这并不是那么困难:我的类包含指向(不透明)C类型的指针,其中构造函数调用“create”函数,析构函数调用“destroy”函数,调用方法调用C函数等等,正如您所期望的那样。到目前为止,这很容易。

然而,我遇到的一个问题是如何处理回调。该库有几个表格的入口点

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

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

我想提供包装器,以便可以在回调中使用任何C ++可调用(即函数,函子,lambda,使用std::bind的方法调用等)。然而,仿函数和(捕获)lambda是需要存储在某处的对象,以确保在回调被触发时它们仍然有效。准确地存储它们的位置似乎有问题...我不能将它们放在堆上,因为它们不能被删除,并且我不能(轻松)使用静态变量,因为我的库只有标题性质

有没有人可以在这种情况下使用任何建议/巧妙的想法/黑客?

提前致谢。

对于nm,如果你看到这一点:前几天为混淆道歉,我被抓了关于工作时间的个人项目发布这个问题所以最好删除它,它只有5个视图当时所以我以为我逃脱了它,但显然不是。如果您不介意再次输入,我会对您的答案感兴趣吗?

1 个答案:

答案 0 :(得分:1)

将订阅句柄和回调对象放在单个订阅包装器中。然后,只要用户希望从您的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; } );