0

QT: Шаблонизированный класс с Q_OBJECT

3

Вопрос: Возможность использования шаблонного класса, наследующего от QObject, с макросом Q_OBJECT

Здравствуйте! У меня возникла проблема с использованием шаблонного класса, который должен наследоваться от QObject и содержать макрос Q_OBJECT в своем объявлении.

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

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

Буду признателен за любые советы или решения!

3 ответ(ов)

0

Вам не удастся смешать шаблоны (template) и 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
{
    ...

Таким образом, вы создаете класс SignalsSlots, который наследуется от QObject и включает в себя определенные слоты и сигналы. Затем, ваш шаблонный класс Abstraction может наследоваться от SignalsSlots. Убедитесь, что классы, которые вы собираетесь использовать как шаблоны, соответствуют требованиям Qt и не конфликтуют с макросами метаобъектов.

0

Принимая во внимание некоторые ограничения, вы можете реализовать это. Сначала ознакомьтесь (если еще не знакомы) с документом по ссылке: https://doc.qt.io/archives/qq/qq16-dynamicqobject.html — это поможет вам в реализации.

Что касается ограничений: вы можете создать шаблонный класс QObject, т.е. шаблонный класс, производный от QObject, но:

  1. Не говорите moc компилировать его.
  2. Q_OBJECT — это просто макрос, и вам нужно заменить его на его реальное содержимое, которое представляет собой виртуальный интерфейс и кое-что еще 😃
  3. Реализуйте активацию QMetaObject (упомянутый выше виртуальный интерфейс, будьте осторожны с объектной информацией, которая также поступает от Q_OBJECT) и другую функциональность, и у вас получится шаблонный QObject (даже с шаблонными слотами).
  4. Но, как я успел заметить, есть один недостаток — вы не можете просто использовать этот класс в качестве базового для другого класса.
  5. Существуют и другие недостатки, но я думаю, что более подробное исследование покажет вам их.

Надеюсь, это будет полезно.

0

В настоящее время невозможно смешивать шаблоны и 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){ /* Делает что-то */}
};

Желаемое использование, но не компилируется:

MySignalClass a;
MySlotClass<int> b;

QObject::connect(&a, SIGNAL(signal_valueChanged(int)),
                 &b, SLOT(slot_setValue(int)));

Ошибка: Шаблонные классы не поддерживаются Q_OBJECT (для MySlotClass).

Решение с использованием нового синтаксиса 'connect':

// Здесь ничего не изменилось
class MySignalClass : public QObject {
  Q_OBJECT
public:

signals:
  void signal_valueChanged(int newValue);
};

// Убрали Q_OBJECT и ключевое слово slots
template<class T>
class MySlotClass : public QObject {  // Наследование по-прежнему требуется
public:
  void slot_setValue(const T& newValue){ /* Делает что-то */}
};

Теперь мы можем создавать экземпляры нужных объектов 'MySlotClass' и подключать их к соответствующим сигналам.

MySignalClass a;
MySlotClass<int> b;

connect(&a, &MySignalClass::signal_valueChanged,
        &b, &MySlotClass<int>::slot_setValue);

Заключение: Использование слотов-шаблонов возможно. Испускание сигналов шаблонов не работает, так как возникнет ошибка компиляции из-за отсутствия Q_OBJECT.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь