2010-03-15 36 views
8

我正在開發一個使用Qt的科學數據採集應用程序。由於我不是Qt的深度專家,因此我希望有一些體系結構在下列問題上提出建議:Qt SIGNAL的體系結構,具有子類特定的模板參數類型

該應用程序支持多個硬件採集接口,但我希望在這些接口之上提供一個通用API接口。每個接口都有一個樣本數據類型和一個數據單位。因此,我將每個設備的樣本矢量表示爲Boost.Units數量的std::vector(即std::vector<boost::units::quantity<unit,sample_type> >)。我想使用多播風格架構,每個數據源都將新收到的數據廣播給一個或多個感興趣的用戶。 Qt的Signal/Slot機制非常適合這種風格。所以,我希望每個數據源發出一個信號,如

typedef std::vector<boost::units::quantity<unit,sample_type> > SampleVector 
signals: 
    void samplesAcquired(SampleVector sampleVector); 

適用於該設備的單位和sample_type。由於元對象編譯器不支持temparted QObject子類,因此似乎沒有辦法爲定義samplesAcquired Signal的所有數據源設置(tempalted)基類。換句話說,以下不會工作:

template<T,U> //sample type and units 
class DataSource : public QObject { 
    Q_OBJECT 
    ... 
    public: 
    typedef std::vector<boost::units::quantity<U,T> > SampleVector 
    signals: 
    void samplesAcquired(SampleVector sampleVector); 
}; 

我已經能夠拿出最好的選擇是兩個層次的方法:

template<T,U> //sample type and units 
class IAcquiredSamples { 
    public: 
     typedef std::vector<boost::units::quantity<U,T> > SampleVector 
     virtual shared_ptr<SampleVector> acquiredData(TimeStamp ts, unsigned long nsamples); 
}; 

class DataSource : public QObject { 
    ... 
    signals: 
     void samplesAcquired(TimeStamp ts, unsigned long nsamples); 
}; 

samplesAcquired信號現在爲收購提供了時間戳和樣本數量,客戶必須使用IAcquiredSamples API來檢索這些樣本。顯然數據源必須繼承DataSource和IAcquiredSamples

這種方法的缺點似乎是在API簡單性方面的損失......如果客戶端可以在連接的插槽中獲得採集的樣本,那將會更好。能夠使用Qt的排隊連接也會使線程問題更容易,而不必在每個子類中的acquiredData方法中管理它們。

另一種可能性是使用QVariant參數。這必然使子類上的責任將其特定的樣本向量類型註冊爲Q_REGISTER_METATYPE/qRegisterMetaType。沒有什麼大不了的。但是,基類的客戶端將無法知道值類型是什麼類型,除非標記結構也與信號一起傳遞。我認爲這個解決方案至少與上面的解決方案一樣複雜,因爲它迫使抽象基類API的客戶端處理類型系統的一些更粗糙的方面。

那麼,有沒有辦法實現模板化信號參數?有沒有比我建議的更好的建築?

+0

我認爲它可以更容易理解,如果你給這個std :: vector的Boost.Units數量的使用僞代碼 它需要運行時多態嗎? – user204724 2010-03-18 13:13:07

+0

我不認爲有比你現有的兩個更好的解決方案。您是否考慮過使用模板參數可以使用的Boost Signals或Signals2? – baysmith 2010-03-27 02:56:21

回答

1

一個簡化到你的雙層方法是將QObject類作爲類模板的非模板化基礎像

class DataSourceBase : public QObject { 
    Q_OBJECT 
    ... 
    signals: 
     void samplesAcquired(TimeStamp ts, unsigned long nsamples); 
}; 

template<T,U> //sample type and units 
class DataSource : public DataSourceBase { 
    public: 
     typedef std::vector<boost::units::quantity<U,T> > SampleVector 
     virtual shared_ptr<SampleVector> acquiredData(TimeStamp ts, unsigned long nsamples); 
}; 

。注意的缺點,這種方法是,因爲你不能在類模板中使用Q_OBJECT宏有關於它的Qt的元對象系統中沒有的信息。

1

Qt不喜歡從QObject繼承的類模板。如果您不需要QObject的運行時自檢,則可能需要使用Boost.Signals,而不是此問題。但是,在Qt項目中引入Boost.Signals庫可能有點困難。在Boost.Signals中,signals是命名空間,而Qt #define s signalprotected。在引入Boost.Signals之前,您應該確保您的Qt項目編譯爲QT_NO_KEYWORDS(qmake中的CONFIG += no_keywords)。

0

你其實可以與模板一起使用Qt類,而對代碼的修改很少。

Qt類和模板的問題是生成元對象信息的moc工具,它根本不知道模板,但生成的代碼不是需要來自Moc。

您可以使用Verdigris創建您的C++/QObject類,與模板一起工作,沒有任何問題繞過此類代碼的moc步驟。

相關問題