0

抱歉可能重复,但我不理解我找到的示例和代码片段。

我有一个名为“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++ 完全陌生,所以如果我正在做一些“禁止”或混淆某些术语,我想说声抱歉。

问题是:如何将我的类函数(成员函数?)传递给库的“setHandleAfterTouch”函数?

这不起作用:

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

...我的 IDE 说

调用 usb_midi_class:setHandleAfterTouch(void (EncoderWrapper::*)(byte, byte)) 没有匹配函数

我也试过

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

但这行不通……而且我不明白这一点。

非常感谢每个帮助 ;-)

4

1 回答 1

1

函数指针和成员函数指针有不同的类型。你可以自己做:

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

这将允许您发送带有捕获的 lambda,并在其中调用您的成员函数:

//  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函数静态。如果是静态的,它的指针就不是成员函数指针,而是普通的函数指针。

于 2017-08-20T14:34:23.597 回答