2

I am trying to pass a class internal function as a callback function within the class. The error behavior is similar to this problem. Whatsoever, I was unable to construct working code based on that question's answer.

I try to pass over a callback function from within the class,in order to create a finite state machine, inspired by the examples I found on adafruit regarding multithreading. The idea is, that each state can call his successor. The class itself then represents the state machine and I just will call its update function.

While the following code does not resemble this utility, it resembles the problem in a minimal example (based on this larger codepiece):

class MyClass
{
  const byte theAnswer = 42;
  void (*myCallback)();

  void setCallback(void (*callback)())
  {
    myCallback = callback;
  }

  public:

  void print_info()
  {
    Serial.println(theAnswer);
  }

  void call()
  {
    myCallback();
  }

   MyClass()
  {
    setCallback(&MyClass::print_info);
  }
};


MyClass AClassOfItsOwn();

void setup() 
{
  Serial.begin(9600);
  while (! Serial); // Wait until Serial is ready
}

void loop() 
{
  AClassOfItsOwn.call();
  return;
}

I get the following error code returned:

...testscript.ino: In constructor 'MyClass::MyClass()':

testscript:25: error: no matching function for call to 'MyClass::setCallback(void (MyClass::*)())'

     setCallback(&MyClass::print_info);

                                     ^

...\testscript.ino:25:41: note: candidate is:

...\testscript.ino:6:12: note: void MyClass::setCallback(void (*)())

   void setCallback(void (*callback)())

        ^

...\testscript.ino:6:12: note: no known conversion for argument 1 from 'void (MyClass::)()' to 'void ()()'

...\testscript.ino: In function 'void loop()':

testscript:40: error: request for member 'call' in 'AClassOfItsOwn', which is of non-class type 'MyClass()'

   AClassOfItsOwn.call();

                  ^

exit status 1 no matching function for call to 'MyClass::setCallback(void (MyClass::*)())'


fun times with polymorphism

This is code we discussed during looking for a solution. I leave it here for future reference.

I tried creating an instance of this wrapper within the actual class to hold the callback, but that did not work either.

class CallbackWrapper
{
  void (*myCallback)();
  public:

  void call()
  {
    myCallback();
  }

  void setCallback(void (*callback)())
  {
    myCallback = callback;
  }
};

class MyClass : public CallbackWrapper
{
  const byte theAnswer = 42;
  public:

  void print_info()
  {
    Serial.println(theAnswer);
  }

   MyClass()
  {
    CallbackWrapper::setCallback(&MyClass::print_info);
  }
};

trying to store the callback function in a wrapping class (also not working, '((MyClass*)this)->MyClass::CBW' does not have class type)

class CallbackWrapper
{
  void (*myCallback)();
  public:

  void call()
  { myCallback(); }

  void setCallback(void (*callback)())
  { myCallback = callback; }
};

class MyClass 
{
  const byte theAnswer = 42;
  CallbackWrapper CBW();
  public:
  void print_info() { Serial.println(theAnswer); }
  void call() { CBW.call(); }
  MyClass()
  { CBW.setCallback(&MyClass::print_info); }
};

An update on why I want to change the callback function during runtime. Here I try to randomly change the callback function:

class MyClass 
{
  CallbackWrapper CBW();
  public:
  void do_this() { Serial.println("doing this"); }
  void do_that() { Serial.println("doing that"); }
  void call() 
  { 
    CBW.call();
    if (rand() > 0.5)
    {
      CBW.setCallback(&MyClass::do_this)
    }
    else
    {
      CBW.setCallback(&MyClass::do_that)
    }
  }
   MyClass()
  {  }
};

For discussion with Michail

class CallbackWrapper
{
  public:
  void (*myCallback)();
  void call()
  { myCallback(); }

  virtual void setCallback(void (*callback)())
  {  }
};

class MyClass : public CallbackWrapper
{
  public:
  void setCallback(void (*callback)())
    { myCallback = callback; }
  void do_this() { Serial.println("doing this"); }
  void do_that() { Serial.println("doing that"); }
  void call() 
  { 
    CallbackWrapper::call();
    if (rand() > 0.5)
    { setCallback(&MyClass::do_this); }
    else
    { setCallback(&MyClass::do_that); }
  }
   MyClass()
  {  }
};
6

Unless you specifically limit yourself to one single class for a callback (i.e., include the class name in the function pointer specification) then you can ONLY use static member functions as callbacks.

static member functions appear as a normal function, not a member function, so don't have the implied MyClass *this as a first parameter.

If you want to allow member functions that aren't static you will have to make use of polymorphism and have a single base class that all classes which provide a callback function will inherit from. Then you limit the callback function pointer to be members of that base class.

It is possible to do it if you are happy to limit to just one class, though the syntax is rather cryptic:

class MyClass 
{
  const byte theAnswer = 42;
  void (MyClass::*myCallback)();

public:

  void call() {
    (this->*myCallback)();
  }

  void setCallback(void (MyClass::*callback)()) {
    myCallback = callback;
  }

  void print_info() {
    Serial.println(theAnswer);
  }

  MyClass() {
    setCallback(&MyClass::print_info);
  }
};

Using polymorphism you can only pass a callback function that is a member of the parent class, so it looks like that method may be out.

  • So, I tried creating a base class CallbackWrapper which has the callback functionality ((*myCallback)(), setCallback() and call()). I inherited MyClass from that base class. I tried to hook up my Callback using CallbackWrapper::setCallback(&MyClass::print_info()). Return is no matching function for call to 'MyClass::setCallback(void (MyClass::*)())' – Faultier Jan 15 '16 at 13:49
  • I can't visualize what you are describing. Polymorphism is a tricky subject and easy to get wrong. – Majenko Jan 15 '16 at 13:52
  • I abuse the edit question to post my futile try. (: – Faultier Jan 15 '16 at 13:57
  • That's not abuse - that's what it's there for. You're not using polymorphism in the right way - you need to think along the lines of an "interface" as Java has it. I'll see about an example. – Majenko Jan 15 '16 at 13:58
  • Actually, I am not sure even I can do it using polymorphism - it's incredibly tricky. Can you have just one standard function name that will always be the callback function in a class? – Majenko Jan 15 '16 at 14:08

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.