如何让编译器代替我复制这段代码?

问题描述 投票:0回答:1

我正在开发一个由 MIDI 消息控制的合成器,有时同时来自多个 MIDI 源。它基于 Teensy 4.1。

我编码使用的第一个源是USB设备MIDI——简单:在setup()中设置8个回调并在loop()中调用usbMIDI.read()。

我对其进行编码以使用的第二个源是USB Host MIDI。然而,我最终得到了重复的代码——所有回调设置代码和loop()中的read()调用。

然后我添加了更多 USB 主机 MIDI 源对象,创建了一个指向主机对象的指针数组,现在我在 setup() 和 Loop() 中迭代该数组...但仍然有该代码的副本用于 USB 设备接口。

供参考:

void setup()
{
// USB Device
    usbMIDI.setHandleNoteOff(myNoteOff);
    usbMIDI.setHandleNoteOn(myNoteOn);
    usbMIDI.setHandlePitchChange(myPitchChange);
...
// USB Host
    for(uint8_t i = 0; i < CNT_MIDI; i++)
    {
        midiDevices[i]->setHandleNoteOff(myNoteOff);
        midiDevices[i]->setHandleNoteOn(myNoteOn);
        midiDevices[i]->setHandlePitchChange(myPitchChange);
...
    }
}
...
void loop()
{
    usbMIDI.read();

    for(uint8_t i = 0; i < CNT_MIDI; i++)
       midiDevices[i]->read();
...
}

这两个类(USBdevice:usb_midi_class,USBhost:MIDIDeviceBase)的接口对于这些调用(read(),setHandle ...(函数指针))是相同的,但由于它们没有共同的基类,所以我不能只需将 USB 设备 MIDI 对象添加到 USB 主机指针数组即可。

现在,我想通过 Teensy 的硬件串行端口之一添加一个 5 针 DIN MIDI 端口,并且会拥有相同调用的三个副本......我想知道是否有更好的方法。

我的目标是在所有这三种类型上调用同名成员函数,而不需要将这些调用写入三次。如果编译器这样做,我不会介意。我也不打算在 setup() 之后添加或删除对象;我知道编译时的来源是什么。

这感觉像是模板的工作,但对我来说,在不以另一种方式复制所有代码的情况下如何完成此任务并不明显。

例如,我想我可以编写一个公共基类,9个虚函数,并创建一个派生模板类来继承它,然后定义这9个虚函数,例如:

class Wrapper { public: virtual bool read(uint8_t channel) = 0; virtual ~Wrapper() = 0; ... }; template <class T> class TemplateWrapper : public Wrapper { private: T* wrapped; public: TemplateWrapper(T* w) : wrapped(w) {} bool read(uint8_t channel) { return wrapped->read(channel); } ... };
但它仍然让我多次重写代码,只是在不同的地方。另外,我必须用函数指针写出 8 个签名。

有更好的方法吗?

c++ oop templates dry teensy
1个回答
0
投票
使用模板是一个好主意,但您不需要为每个对象实际创建一个基类。您可以创建一个函数接受对某些模板化参数的引用并在其上调用您的函数。

template <typename T> void setupDevice(T& device) { device.setHandleNoteOff(myNoteOff); device.setHandleNoteOn(myNoteOn); device.setHandlePitchChange(myPitchChange); }
您还可以重载该函数以接受指针而不是引用,因为您在显示的代码中使用了两者。

template <typename T> void setupDevice(T* device) { device->setHandleNoteOff(myNoteOff); device->setHandleNoteOn(myNoteOn); device->setHandlePitchChange(myPitchChange); }
    
© www.soinside.com 2019 - 2024. All rights reserved.