2010-03-15 59 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步骤。