Home > OS >  c callbacks to another member function
c callbacks to another member function

Time:12-02

I have a question on callbacks. Previously, I am associating my callbacks to a class Q

class Q{
   using Callback = std::function<void(char*, int)>;
   Q:Q();
   Q:~Q();

   void Q::RegisterCB(Callback callbackfunc)
   {
       callback_func = callbackfunc;
   }

   void Q:someEvent()
   {
      callback_func();
   }
};

void handleCallback( char*, int)
{
   // perform some routine

}

// from my main file
int main()
{
   Q q;
   q.RegisterCB(&handleCallback);

}

It works well for me. However, when I need to transfer the handleCallback function to another class for cleaner code. I have problem with using same code

class R{

   void R::handleCallback( char*, int)
   {
   // perform some routine

   }

   void R::someOp()
   {
       // q is some member variables of R
       q.RegisterCB(&R::handleCallback, this);

   }

};

However, i run into some problems of saying there is a "no matching function for call to .....". I thought it was just simply assigning from function name to class function name

May I have a hint to where I might go wrong?

Regards

CodePudding user response:

&R::handleCallback has the type void (R::*)(char*, int), which is not convertible to std::function<void(char*, int)>.
Also, RegisterCB takes one argument, not two.

The most straightforward fix is to wrap the call in a lambda function,

q.RegisterCB([this](char* p, int x) { handleCallback(p, x); }); 

CodePudding user response:

Example on how to use a lambda function to register a member function of an instance of R as event handler. (I replaced char* with string_view out of habit, it's not essential for this example). The use of "const" wherever you can is a recommendation.

#include <functional>
#include <string_view>
#include <iostream>

class Q
{
public:
   // use const arguments, the callback is not supposed to change them
   // just passing information on to callback
   using callback_t = std::function<void(const std::string_view&, const int)>;
   
   // initialize callback with a (lambda) function that does nothing
   // this prevents the need for a check if callback has been set or not
   // (Pattern : Null Strategy)
   Q() :
       m_callback_func( [](const std::string_view&,const int) {} ) 
   {
   }

   ~Q() = default;

   void RegisterCallback(callback_t fn)
   {
       m_callback_func = fn;
   }

   void Event(const std::string_view& string, const int value)
   {
      m_callback_func(string,value);
   }

private:
    callback_t m_callback_func;
};

void handleCallback(const std::string_view& string, const int value)
{
    std::cout << string << ", " << value << "\n";
}

class R
{
public:
    void handleCallback(const std::string_view& string, const int value)
    {
        std::cout << string << ", " << value << "\n";
    }
};

// from my main file
int main()
{
    Q q1;
    q1.RegisterCallback(handleCallback);
    q1.Event("Hello", 42);

    // to pass a callback to an instance of a class 
    // you can use a lambda function https://en.cppreference.com/w/cpp/language/lambda
    R r;
    Q q2;

    q2.RegisterCallback([&r](const std::string_view& string, const int value)
    {
        r.handleCallback(string,value);
    });

    q2.Event("World",21);
    return 0;
}
  • Related