QT:模板化的Q_OBJECT类

BЈо*_*вић 40 c++ qt templates signals-slots

是否有可能有一个模板类,它继承自QObject(并在其声明中有Q_OBJECT宏)?

我想创建像插槽适配器这样的东西,它会做一些事情,但插槽可以采取任意数量的参数(参数的数量取决于模板参数).

我只是尝试这样做,并得到链接器错误.我猜这个模板类没有调用gmake或moc.有没有办法做到这一点?也许通过显式实例化模板?

小智 34

无法混合模板和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
{...
Run Code Online (Sandbox Code Playgroud)

  • 简单的概念分离......! (2认同)

小智 10

考虑到一些限制:你可以.首先请熟悉(如果已经没有)https://doc.qt.io/archives/qq/qq16-dynamicqobject.html. - 这将有助于改变它.关于限制:你可以有一个模板QObject类,即从QObject派生的模板类,但是:

  1. 不要告诉moc编译它.
  2. Q_OBJECT只是一个宏,你必须用真正的内容替换它,这是虚拟接口和其他东西:)
  3. 实现QMetaObject激活(上面提到的虚拟接口并注意对象信息数据,也来自Q_OBJECT)和其他一些功能,你将有模板QObject(即使有模板插槽)
  4. 但是当我设法抓住一个回撤时 - 不可能 简单地使用这个类作为另一个类的基础.
  5. 还有一些其他缺点 - 但我认为详细调查会告诉你.

希望这会有所帮助.

  • 如果没有深入研究这一点,沿着这条路尝试重新实现 Q_OBJECT 宏,这样我就可以在模板化类中使用信号和槽,这真的感觉像是一场维护噩梦。您有如何成功完成此操作的示例吗? (2认同)

Ano*_*ous 5

仍然不可能混合模板和 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. */}
};
Run Code Online (Sandbox Code Playgroud)

期望的用法但无法编译:

MySignalClass a;
MySlotClass<int> b;

QObject::connect(&a, SIGNAL(signal_valueChanged(int)),
                 &b, SLOT(slot_setValue(int)));
Run Code Online (Sandbox Code Playgroud)

错误:Q_OBJECT 不支持模板类(对于 MySlotClass)。

使用新的“连接”语法的解决方案:

// 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. */}
};
Run Code Online (Sandbox Code Playgroud)

现在我们可以实例化所需的“MySlotClass”对象并将它们连接到适当的信号发射器。

  MySignalClass a;
  MySlotClass<int> b;

  connect(&a, &MySignalClass::signal_valueChanged,
          &b, &MySlotClass<int>::slot_setValue);
Run Code Online (Sandbox Code Playgroud)

结论:使用模板槽是可能的。发出模板信号不起作用,因为缺少 Q_OBJECT 会出现编译器错误。


BЈо*_*вић 1

我尝试显式实例化模板,并得到以下结果:

core_qta_qt_publisheradapter.hpp:96: 错误: Q_OBJECT 不支持模板类

我想这回答了我的问题。

编辑

实际上,如果我将整个模板类定义放在标头中,那么 qt 预处理器不会处理它,然后我会收到链接器错误。因此,如果我添加缺少的方法,它一定可以做到。

编辑#2

这个库正是我想要的——使用自定义信号/槽机制,其中槽没有定义签名。