Подтвердить что ты не робот

QT: Templated класс Q_OBJECT

Возможно ли иметь класс шаблона, который наследует от QObject (и имеет в нем макрос Q_OBJECT)?

Я хотел бы создать что-то вроде адаптера для слотов, что бы что-то сделать, но слот может принимать произвольное количество аргументов (количество аргументов зависит от аргумента шаблона).

Я просто попытался сделать это и получил ошибки компоновщика. Я думаю, gmake или moc не получают вызов этого класса шаблона. Есть ли способ сделать это? Может быть, явно создавая шаблоны?

4b9b3361

Ответ 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.