C++ QT:模板化的 Q_OBJECT 类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4397478/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:18:42  来源:igfitidea点击:

QT : Templated Q_OBJECT class

c++qttemplatessignals-slots

提问by B?ови?

Is it possible to have a template class, which inherit from QObject (and has Q_OBJECT macro in it's declaration)?

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

I would like to create something like adapter for slots, which would do something, but the slot can take arbitrary number of arguments (number of arguments depends on the template argument).

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

I just tried doing it, and got linker errors. I guess gmake or moc is not getting called on this template class. Is there a way to do this? Maybe by explicitly instantiating templates?

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

回答by Jonas W

It is not possible to mix template and Q_OBJECT but if you have a subset of types you can list the slots and signals like this:

混合模板和 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
{...

回答by milyaaf

Taking into account some restrictions: you can. First please became familiar (if already not) https://doc.qt.io/archives/qq/qq16-dynamicqobject.html. - it will help to imlement it. And about restrictions: you can have a template QObject class i.e. template class derived from QObject, but:

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

  1. Do not tell the moc to compile it.
  2. Q_OBJECT is just a macro and you have to replace it by it real content which is virtual interface and something else :)
  3. Implement QMetaObject activation (above mentioned virtual interface and be caution with object info data, which is also come from Q_OBJECT) and some else functionality and you will have template QObject (even with template slots)
  4. But as I managed to catch the one draw back - it is not possible to simplyuse this class as a base for another class.
  5. There are some other drawbacks - but I think the detail investigation will show you them.
  1. 不要告诉 moc 编译它。
  2. Q_OBJECT 只是一个宏,您必须用它替换它的真实内容,即虚拟界面和其他内容:)
  3. 实现 QMetaObject 激活(上面提到的虚拟接口,注意对象信息数据,它也来自 Q_OBJECT)和其他一些功能,你将拥有模板 QObject(即使有模板槽)
  4. 但是当我设法抓住一个缺点时 - 不可能 简单地使用这个类作为另一个类的基础。
  5. 还有一些其他缺点 - 但我认为详细调查会告诉你它们。

Hope this will helpful.

希望这会有所帮助。

回答by Anonymous

It is still not possible to mix templates and Q_OBJECT but depending on your use case you may use the new 'connect'-syntax. This allows at least the usage of template-slots.

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

Classical non-working approach:

经典的非工作方法:

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. */}
};

Desired usage but not compilable:

所需用途但不可编译:

MySignalClass a;
MySlotClass<int> b;

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

Error: Template classes not supported by Q_OBJECT (For MySlotClass).

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

Solution using new the 'connect'-syntax:

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

// 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. */}
};

Now we can instantiate desired 'MySlotClass'-objects and connect them to appropriate signal emitters.

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

  MySignalClass a;
  MySlotClass<int> b;

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

Conclusion:Using template-slots is possible. Emitting template signals is not working since a compiler error will occur due to missing Q_OBJECT.

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

回答by B?ови?

I tried explicitly instantiating templates, and got this :

我尝试显式实例化模板,并得到了这个:

core_qta_qt_publisheradapter.hpp:96: Error: Template classes not supported by Q_OBJECT

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

I guess that answers my question.

我想这回答了我的问题。

EDIT

编辑

Actually, if I place whole template class definition in the header, then the qt preprocessor doesn't process it, and then I get linker errors. Therefore it must be possible to do it, if I add missing methods.

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

EDIT #2

编辑#2

This librarydid exactly what I wanted - to use a custom signal/slot mechanism, where the slot has not-defined signature.

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