【问题标题】:QT : Templated Q_OBJECT classQT:模板化的 Q_OBJECT 类
【发布时间】:2011-05-22 19:12:26
【问题描述】:

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

我想为插槽创建类似适配器的东西,它会做一些事情,但插槽可以接受任意数量的参数(参数数量取决于模板参数)。

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

【问题讨论】:

标签: c++ qt templates signals-slots


【解决方案1】:

我尝试显式实例化模板,结果如下:

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

我想这回答了我的问题。

编辑

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

编辑#2

This library 完全符合我的要求 - 使用自定义信号/插槽机制,其中插槽具有未定义的签名。

【讨论】:

    【解决方案2】:

    考虑到一些限制:可以。 首先请熟悉(如果还没有)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 宏,这样我就可以在模板类中使用信号和槽,这真的感觉像是一场维护噩梦。你有一个成功的例子吗?
    【解决方案3】:

    不能混合使用模板和 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 等效项中声明为虚拟抽象并在类模板中定义。
    • 你能解释一下吗? SignalsSlots 类不是模板类,那么我如何在信号的签名中使用模板参数?例如,如果我想做这样的事情:void someSignal(T value).
    • 您只能将子集与模板一起使用,即在示例中;整数、浮点数、双精度、布尔值、开关状态。添加您需要支持的所有类型。我觉得QT 5版本可以混用template和Q_OBJECT,但是没试过。
    • 我希望在 Abstraction 类示例中多写几行。您是否创建了与您要覆盖的插槽同名的常规方法?最后 10% 令人困惑
    【解决方案4】:

    仍然无法混合使用模板和 Q_OBJECT,但根据您的用例,您可以使用新的“连接”语法。这至少允许使用模板槽。

    经典的非工作方法:

    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)。

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

    // 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 会发生编译器错误,因此无法发出模板信号。

    【讨论】:

    • 你的意思是发出信号仍然不起作用,对吧? (谢谢)
    • @Anonymous 我对此感到非常高兴,但我收到“错误:类声明缺少 Q_OBJECT 宏” - 自 2017 年以来它是否发生了变化?
    猜你喜欢
    • 2021-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多