我正在为一个流行的开源C库编写C ++ 11包装器,提供RAII和您期望的所有其他细节。包装器将只是标头(所以只需要链接到原始的C lib),另外我要坚持的一个原则是包装器应该尽可能“零开销”,是,当启用优化时,应该内联所有内容,以便只保留C函数调用。
在大多数情况下,这并不是那么困难:我的类包含指向(不透明)C类型的指针,其中构造函数调用“create”函数,析构函数调用“destroy”函数,调用方法调用C函数等等,正如您所期望的那样。到目前为止,这很容易。
然而,我遇到的一个问题是如何处理回调。该库有几个表格的入口点
typedef <function signature> CallbackType;
void set_callback(CallbackType cb, void* data);
这样底层C库将cb
和data
存储在静态变量中,并且当特定事件发生时,将触发回调并将data
与其他参数一起传递回它
我想提供包装器,以便可以在回调中使用任何C ++可调用(即函数,函子,lambda,使用std::bind
的方法调用等)。然而,仿函数和(捕获)lambda是需要存储在某处的对象,以确保在回调被触发时它们仍然有效。准确地存储它们的位置似乎有问题...我不能将它们放在堆上,因为它们不能被删除,并且我不能(轻松)使用静态变量,因为我的库只有标题性质
有没有人可以在这种情况下使用任何建议/巧妙的想法/黑客?
提前致谢。
对于nm,如果你看到这一点:前几天为混淆道歉,我被抓了关于工作时间的个人项目发布这个问题所以最好删除它,它只有5个视图当时所以我以为我逃脱了它,但显然不是。如果您不介意再次输入,我会对您的答案感兴趣吗?
答案 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; } );