0

sorry for possible duplicates, but I didn't understand the examples and codes snippets I found.

I have a class named "EncoderWrapper" which includes some functions. One of these functions is called "onAfterTouch" and is declared in the "EncoderWrapper.h" file.

void onAfterTouch(byte channel, byte pressure);

The functions will become a callback for another class function of a library I use

inline void setHandleAfterTouch(void (*fptr)(uint8_t channel, uint8_t pressure)) {                
    usb_midi_handleAfterTouch = fptr;
};

Note: I'm totally new to C++, so I want to say sorry if I'm doing some "no-gos" or mixing up some terms.

The question is: How can I pass my class function (member function?) to that "setHandleAfterTouch" function of the library?

This won't work:

void EncoderWrapper::attachMIDIEvents()
{
    usbMIDI.setHandleAfterTouch(&EncoderWrapper::onAfterTouch);
}

... my IDE says

no matching function for call usb_midi_class:setHandleAfterTouch(void (EncoderWrapper::*)(byte, byte))

I've also tried

usbMIDI.setHandleAfterTouch((&this->onAfterTouch));

But this won't work ... and I don't get the approach on that.

Every Help is very appreciated ;-)

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
pixel-shock
  • 67
  • 1
  • 9

1 Answers1

1

Function pointer and member function pointer have different types. You can it for yourself:

struct Test {
    void fun();
};

int main() {
    void(*ptr)() = &Test::fun; // error!
}

Instead, member function pointer need this syntax:

void(Test::*fun)() = &Test::fun; // works!

Why you ask? Because member function need an instance to be called with. And calling that function have a special syntax too:

Test t;

(t.*funptr)();

To accept member function pointer, you'll need to change your code to this:

inline void setHandleAfterTouch(void(EncodeWrapper::*fptr)(uint8_t, uint8_t)) {                
    usb_midi_handleAfterTouch = fptr;
};

Since it's rather limiting accepting only the functions from one class, I recommend using std::function:

inline void setHandleAfterTouch(std::function<void(uint8_t, uint8_t)> fptr) {                
    usb_midi_handleAfterTouch = std::move(fptr);
};

This will allow you to send lambda with captures, and call your member function insode it:

//  we capture this to use member function inside
//                           v---
usbMIDI.setHandleAfterTouch([this](uint8_t, channel, uint8_t pressure) {
    onAfterTouch(channel, pressure);
});

It seems you can't change, and by looking quickly at the API, it doesn't seem you have access to a state object.

In that case, if you want to use your member function, you need to introduce a global state:

// global variable
EncodeWrapper* encode = nullptr;

// in your function that sets the handle
encode = this; //            v--- No capture makes it convertible to a function pointer
usbMIDI.setHandleAfterTouch([](uint8_t, channel, uint8_t pressure) {
    encode->onAfterTouch(channel, pressure);
});

Another solution would be to make onAfterTouch function static. If it's static, it's pointer is not a member function pointer, but a normal function pointer.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • Hi Guillaume, thank you for your reply. I think I got the point, BUT I can't modify the setHandleAfterTouch function, because it's included in a library ... At the moment it sounds like that I can't use the library with my class? https://www.pjrc.com/teensy/td_midi.html – pixel-shock Aug 20 '17 at 14:59
  • Or maybe I should add a getter for the usbMIDI instance and a getter for each callback. And after I instanciated my wrapper class I should use the getter on that instance and set the callback functions? – pixel-shock Aug 20 '17 at 15:07
  • great Guillaume. Thank you very much. I test it asap and let you know if it worked. Maybe you saved my day – pixel-shock Aug 20 '17 at 17:25
  • 1
    Hey Guillaume, **ITS WORKING** ... thank you very much! And sorry for the late reply ... lot of work ... :( – pixel-shock Sep 04 '17 at 12:26