【问题标题】:Using functors/lambdas with C callbacks使用带有 C 回调的函子/lambda
【发布时间】:2014-10-20 02:07:30
【问题描述】:

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

在大多数情况下,这并不难:我有一些类,它们保存指向(不透明)C 类型的指针,构造函数调用“创建”函数,析构函数调用“销毁”函数,方法调用正如您所期望的那样,C 函数等。到目前为止,很容易。

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

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

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

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

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

提前致谢。

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

【问题讨论】:

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


    【解决方案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; } );
    

    【讨论】:

    • 这实际上非常好,我没有真正想过将责任推给用户,但它确实有道理。谢谢,欢迎使用 StackOverflow!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-04
    • 2016-09-20
    • 2013-10-07
    • 1970-01-01
    • 2018-10-15
    • 1970-01-01
    • 2020-06-23
    相关资源
    最近更新 更多