2010-12-09 62 views
28

是否有可能有一個模板類,它從QObject繼承(並且在它的聲明中有Q_OBJECT宏)?QT:模板化的Q_OBJECT類

我想創建類似插槽的適配器,這將做一些事情,但插槽可以採用任意數量的參數(參數數量取決於模板參數)。

我只是試着這樣做,並得到鏈接器錯誤。我猜gmake或moc不會在這個模板類上被調用。有沒有辦法做到這一點?也許通過明確實例化模板?

+0

您是否觀察過包含模型? :) http://linuxtopia.org/online_books/programming_books/c++_practical_programming/c++_practical_programming_134.html – 2010-12-09 11:04:42

+0

@阿門是的,我沒有想到這一點。我認爲qt預處理器會把它啃掉。 – 2010-12-09 11:07:54

回答

1

我想明確模板實例化,並得到了這一點:

core_qta_qt_publisheradapter.hpp:96:錯誤:不是Q_OBJECT

我想這回答我的問題支持模板類。

編輯

其實,如果我把整個模板類定義的標題,然後Qt的預處理器不處理它,然後我得到的鏈接錯誤。因此,如果我添加缺少的方法,就必須做到這一點。

編輯#2

This library也正是我想要的 - 使用自定義的信號/插槽機構,其中的插槽還沒有定義的簽名。

9

考慮到一些限制:你可以。 首先請熟悉(如果已經不是)https://doc.qt.io/archives/qq/qq16-dynamicqobject.html。 - 這將有助於實現它。 而關於限制:你可以從QObject的來源的模板QObject的類,即模板類,但:

  1. 不要告訴建設部編譯。
  2. Q_OBJECT只是一個宏,你必須通過它來代替它真正 內容是虛擬接口和別的東西:)
  3. 實現QMetaObject激活(上面提到的虛擬接口 並謹慎使用對象信息數據,這是也來自 Q_OBJECT)和一些其他的功能,你將有模板 QObject的(即使有模板槽)
  4. 但是,當我設法抓住了一個退 - 這是不可能的 簡單使用這個類作爲另一個班的基地。
  5. 還有一些其他的缺點 - 但我認爲詳細的調查將告訴你他們。

希望這會有所幫助。

23

這是不可能的混合模板和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 
{... 
1

它仍然是不可能的混合模板和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))); 

Error: Template classes not supported by Q_OBJECT (For 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會發生編譯器錯誤。