Search code examples
c++templatesvariadic-templates

Use variadic template for C callback wrapper


I am currently trying to wrap a C library (namele its GTK as training). I wanted to see if I can use variadic templated for the callbacks, as they have varying parameter counts in the callbacks for the signal. I intended to use std::function and variadic templates. Kind of like this:

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;

};

I am pretty new to this, but is this even possible to pass the variadic arguments to a std:function?


Solution

  • but is this even possible to pass the variadic arguments to a std:function?

    I don't understand what you're trying to obtain but... given that the args... are fixed as template parameter of the class, yes: you can.

    With a couple of corrections in your static method: (1) you have to cast data to a cb_data_t pointer (no cb_data) and (2) you have to take in count that cbd is a pointer so you have to call callback() through an arrow operator, not through a point operator

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

    or, maybe better, you can directly pass the last argument as cb_data_t pointer

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

    Note that, receiving the cd_data_t pointer as argument, you're not using the cb_data member.

    The following is a full compiling, and simplified, example

    #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);
     }
    

    But this solution seems to me overcomplicated. Unfortunately I don't understand how do you want use your wrapper so I can't suggest you something simpler.