首页 > 解决方案 > 为 C 回调包装器使用可变参数模板

问题描述

我目前正在尝试包装一个 C 库(将其 GTK 命名为培训)。我想看看我是否可以为回调使用可变参数模板,因为它们在信号的回调中具有不同的参数计数。我打算使用std::function可变参数模板。有点像这样:

template<typename... args> class callback_t { public:
    struct cb_data_t
    {
        std::function<void (args...)> callback;
    };
    // data contains cb_data
    static void callback_from_a_c_function(args... a, void *data)
    {
        cb_data_t *cbd = (cb_data *)data;
        cbd.callback(a...);
    }

private:
    cb_data_t cb_data;

};

我对此很陌生,但这甚至可以将可变参数传递给 astd:function吗?

标签: c++templatesvariadic-templates

解决方案


但这甚至可以将可变参数传递给 std:function 吗?

我不明白你想要获得什么,但是......鉴于它们args...被固定为类的模板参数,是的:你可以。

在您的静态方法中进行了一些更正:(1)您必须强制data转换为cb_data_t指针( no cb_data)和(2)您必须考虑cbd作为指针的计数,因此您必须callback()通过箭头运算符调用,而不是通过点算子

  static void callback_from_a_c_function(args... a, void *data)
   { // ......................VV
     cb_data_t *cbd = (cb_data_t *)data;
     cbd->callback(a...);
   } // ^^

或者,也许更好,您可以直接将最后一个参数作为cb_data_t指针传递

  static void callback_from_a_c_function(args... a, cb_data_t * cbd)
   { cbd->callback(a...); }

请注意,接收cd_data_t指针作为参数,您没有使用该cb_data成员。

以下是完整的编译和简化示例

#include <iostream>
#include <functional>

template <typename ... args>
struct callback_t
 {
   struct cb_data_t
    { std::function<void (args...)> callback; };

   static void callback_from_a_c_function(args... a, cb_data_t * cbd)
    { cbd->callback(a...); }
 };

extern "C"
 {
   void foo (int, long)
    { std::cout << "foo!" << std::endl; }
 }

int main ()
 {
   callback_t<int, long>::cb_data_t  cbd{&foo};
   callback_t<int, long>::callback_from_a_c_function(0, 1l, &cbd);
 }

但在我看来,这个解决方案过于复杂。不幸的是,我不明白你想如何使用你的包装器,所以我不能建议你更简单的东西。


推荐阅读