可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Is it possible to have a template class, which inherit from QObject (and has Q_OBJECT macro in it's declaration)?
I would like to create something like adapter for slots, which would do something, but the slot can take arbitrary number of arguments (number of arguments depends on the template argument).
I just tried doing it, and got linker errors. I guess gmake or moc is not getting called on this template class. Is there a way to do this? Maybe by explicitly instantiating templates?
回答1:
It is not possible to mix template and Q_OBJECT but if you have a subset of types you can list the slots and signals like this:
class SignalsSlots : public QObject { Q_OBJECT public: explicit SignalsSlots(QObject *parent = 0) : QObject(parent) {} public slots: virtual void writeAsync(int value) {} virtual void writeAsync(float value) {} virtual void writeAsync(double value) {} virtual void writeAsync(bool state) {} virtual void writeAsync(svga::SSlideSwitch::SwitchState state) {} signals: void readAsynkPolledChanged(int value); void readAsynkPolledChanged(float value); void readAsynkPolledChanged(double value); void readAsynkPolledChanged(bool state); void readAsynkPolledChanged(svga::SSlideSwitch::SwitchState state); }; ... template class Abstraction : public SignalsSlots {...
回答2:
Taking into account some restrictions: you can. First please became familiar (if already not) https://doc.qt.io/archives/qq/qq16-dynamicqobject.html. - it will help to imlement it. And about restrictions: you can have a template QObject class i.e. template class derived from QObject, but:
- Do not tell the moc to compile it.
- Q_OBJECT is just a macro and you have to replace it by it real content which is virtual interface and something else :)
- Implement QMetaObject activation (above mentioned virtual interface and be caution with object info data, which is also come from Q_OBJECT) and some else functionality and you will have template QObject (even with template slots)
- But as I managed to catch the one draw back - it is not possible to simply use this class as a base for another class.
- There are some other drawbacks - but I think the detail investigation will show you them.
Hope this will helpful.
回答3:
I tried explicitly instantiating templates, and got this :
core_qta_qt_publisheradapter.hpp:96: Error: Template classes not supported by Q_OBJECT
I guess that answers my question.
EDIT
Actually, if I place whole template class definition in the header, then the qt preprocessor doesn't process it, and then I get linker errors. Therefore it must be possible to do it, if I add missing methods.
EDIT #2
This library did exactly what I wanted - to use a custom signal/slot mechanism, where the slot has not-defined signature.
回答4:
It is still not possible to mix templates and Q_OBJECT but depending on your use case you may use the new 'connect'-syntax. This allows at least the usage of template-slots.
Classical non-working approach:
class MySignalClass : public QObject { Q_OBJECT public: signals: void signal_valueChanged(int newValue); }; template class MySlotClass : public QObject { Q_OBJECT public slots: void slot_setValue(const T& newValue){ /* Do sth. */} };
Desired usage but not compilable:
MySignalClass a; MySlotClass b; QObject::connect(&a, SIGNAL(signal_valueChanged(int)), &b, SLOT(slot_setValue(int)));
Error: Template classes not supported by Q_OBJECT (For MySlotClass).
Solution using new the 'connect'-syntax:
// Nothing changed here class MySignalClass : public QObject { Q_OBJECT public: signals: void signal_valueChanged(int newValue); }; // Removed Q_OBJECT and slots-keyword template class MySlotClass : public QObject { // Inheritance is still required public: void slot_setValue(const T& newValue){ /* Do sth. */} };
Now we can instantiate desired 'MySlotClass'-objects and connect them to appropriate signal emitters.
MySignalClass a; MySlotClass b; connect(&a, &MySignalClass::signal_valueChanged, &b, &MySlotClass::slot_setValue);
Conclusion: Using template-slots is possible. Emitting template signals is not working since a compiler error will occur due to missing Q_OBJECT.