извините за возможные дубликаты, но я не понял примеры и фрагменты кода, которые я нашел.
У меня есть класс с именем «EncoderWrapper», который включает в себя некоторые функции. Одна из этих функций называется «onAfterTouch» и объявляется в файле «EncoderWrapper.h».
void onAfterTouch(byte channel, byte pressure);
Функции станут обратным вызовом для другой функции класса библиотеки, которую я использую
inline void setHandleAfterTouch(void (*fptr)(uint8_t channel, uint8_t pressure)) {
usb_midi_handleAfterTouch = fptr;
};
Примечание: я совершенно новичок в C ++, поэтому я хочу извиниться, если я делаю какие-то «не-gos» или смешиваю некоторые термины.
Вопрос заключается в следующем: как я могу передать свою функцию класса (функцию-член?) Этой функции setHandleAfterTouch библиотеки?
Это не сработает:
void EncoderWrapper::attachMIDIEvents()
{
usbMIDI.setHandleAfterTouch(&EncoderWrapper::onAfterTouch);
}
… моя IDE говорит
нет соответствующей функции для вызова usb_midi_class: setHandleAfterTouch (void (EncoderWrapper :: *) (byte, byte))
Я также пытался
usbMIDI.setHandleAfterTouch((&this->onAfterTouch));
Но это не сработает … и я не понимаю этого.
Каждая помощь очень ценится 😉
Указатель на функцию и указатель на функцию-член имеют разные типы. Вы можете это для себя:
struct Test {
void fun();
};
int main() {
void(*ptr)() = &Test::fun; // error!
}
Вместо этого указателю на функцию-член нужен следующий синтаксис:
void(Test::*fun)() = &Test::fun; // works!
Почему ты спрашиваешь? Потому что функция-член должна вызывать экземпляр с. И вызов этой функции также имеет специальный синтаксис:
Test t;
(t.*funptr)();
Чтобы принять указатель на функцию-член, вам нужно изменить код на следующий:
inline void setHandleAfterTouch(void(EncodeWrapper::*fptr)(uint8_t, uint8_t)) {
usb_midi_handleAfterTouch = fptr;
};
Так как это довольно ограничивает прием только функций из одного класса, я рекомендую использовать std::function
:
inline void setHandleAfterTouch(std::function<void(uint8_t, uint8_t)> fptr) {
usb_midi_handleAfterTouch = std::move(fptr);
};
Это позволит вам отправить лямбду с перехватами и вызвать функцию-член insode:
// we capture this to use member function inside
// v---
usbMIDI.setHandleAfterTouch([this](uint8_t, channel, uint8_t pressure) {
onAfterTouch(channel, pressure);
});
Кажется, вы не можете измениться, и, посмотрев быстро на API, вы не сможете получить доступ к объекту состояния.
В этом случае, если вы хотите использовать свою функцию-член, вам нужно ввести глобальное состояние:
// 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);
});
Другое решение было бы сделать onAfterTouch
функция статическая. Если он статический, его указатель не является указателем на функцию-член, а является обычным указателем на функцию.
Других решений пока нет …