QT: Templated класс Q_OBJECT
Возможно ли иметь класс шаблона, который наследует от QObject (и имеет в нем макрос Q_OBJECT)?
Я хотел бы создать что-то вроде адаптера для слотов, что бы что-то сделать, но слот может принимать произвольное количество аргументов (количество аргументов зависит от аргумента шаблона).
Я просто попытался сделать это и получил ошибки компоновщика. Я думаю, gmake или moc не получают вызов этого класса шаблона. Есть ли способ сделать это? Может быть, явно создавая шаблоны?
Ответы
Ответ 1
Нельзя смешивать шаблон и Q_OBJECT, но если у вас есть подмножество типов, вы можете перечислить слоты и сигналы следующим образом:
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 T>
class Abstraction : public SignalsSlots
{...
Ответ 2
Принимая во внимание некоторые ограничения: вы можете.
Сначала прочитайте (если уже не) https://doc.qt.io/archives/qq/qq16-dynamicqobject.html. - это поможет его имитировать.
И об ограничениях: вы можете иметь шаблон QObject class i.e. шаблонный класс, полученный из QObject, но:
- Не сообщайте moc, чтобы скомпилировать его.
- Q_OBJECT - это просто макрос, и вы должны его заменить его реальным
содержимое, которое представляет собой виртуальный интерфейс и что-то еще:)
- Реализация активации QMetaObject (вышеупомянутый виртуальный интерфейс
и будьте осторожны с данными об объекте, которые также поступают из
Q_OBJECT) и некоторые другие функции, и у вас будет шаблон
QObject (даже с слотами для шаблонов)
- Но поскольку мне удалось поймать одного, оттянуть назад - невозможно
просто используют этот класс в качестве базы для другого класса.
- Есть и другие недостатки - но я думаю, что детали
расследование покажет вам их.
Надеюсь, это поможет.
Ответ 3
Я попытался явно создать шаблоны и получил следующее:
core_qta_qt_publisheradapter.hpp: 96: Ошибка: классы шаблонов, не поддерживаемые Q_OBJECT
Я думаю, это отвечает на мой вопрос.
ИЗМЕНИТЬ
На самом деле, если я помещаю определение всего шаблона в заголовок, то препроцессор qt его не обрабатывает, а затем я получаю ошибки компоновщика. Поэтому должно быть возможно сделать это, если я добавлю отсутствующие методы.
РЕДАКТИРОВАТЬ № 2
Эта библиотека сделала именно то, что я хотел - использовать специальный механизм сигнала/слота, в котором слот не определил подпись.
Ответ 4
Смешать шаблоны и Q_OBJECT по-прежнему невозможно, но в зависимости от вашего варианта использования вы можете использовать новый синтаксис connect. Это позволяет, по крайней мере, использовать шаблонные слоты.
Классический нерабочий подход:
class MySignalClass : public QObject {
Q_OBJECT
public:
signals:
void signal_valueChanged(int newValue);
};
template<class T>
class MySlotClass : public QObject {
Q_OBJECT
public slots:
void slot_setValue(const T& newValue){ /* Do sth. */}
};
Желаемое использование, но не компилируемое:
MySignalClass a;
MySlotClass<int> b;
QObject::connect(&a, SIGNAL(signal_valueChanged(int)),
&b, SLOT(slot_setValue(int)));
Ошибка: классы шаблонов, не поддерживаемые Q_OBJECT (для MySlotClass).
Решение с использованием нового синтаксиса "connect":
// Nothing changed here
class MySignalClass : public QObject {
Q_OBJECT
public:
signals:
void signal_valueChanged(int newValue);
};
// Removed Q_OBJECT and slots-keyword
template<class T>
class MySlotClass : public QObject { // Inheritance is still required
public:
void slot_setValue(const T& newValue){ /* Do sth. */}
};
Теперь мы можем создать нужные объекты MySlotClass и подключить их к соответствующим излучателям сигнала.
MySignalClass a;
MySlotClass<int> b;
connect(&a, &MySignalClass::signal_valueChanged,
&b, &MySlotClass<int>::slot_setValue);
Вывод: Возможно использование шаблонов. Испускание шаблонных сигналов не работает, поскольку ошибка компилятора возникает из-за отсутствия Q_OBJECT.