我应该在模板类头文件中包含我需要的所有内容吗?

时间:2014-08-24 13:28:26

标签: c++ qt header-files

当我编写一个类似于字符串的通用模板类时,我遇到了一个两难问题,它给出了一个代表我使用的常见数据结构的QString。我希望我可以在此头文件(#include in .h or .c / .cpp?)中包含最少数量的其他头文件,但也希望它不依赖于它包含的顺序(Header file order)。

基本代码是这样的:

// Some headers

template <typename T>
class PMsg
{
    // Public routines
    public:
        static QString fromType();
        static QString fromValue(T const &val);
}; // PMsg
// Inline definition of all methods in PMsg<T>::fromValue
// Some specialisation
// To be continued...

以下是问题:容器类。我是否应该执行以下操作来拉动所有容器标头以使其正常工作:

// To the beginning
#include <QtCore/QList>
#include <QtCore/QVector>

// After PMsg<T>
template <typename T>
class PMsg<QList<T> >
{
    // Public routines
    public:
        static QString fromType();
        static QString fromValue(QList<T> const &val);
}; // PMsg
// Some definitions

template <typename T>
class PMsg<QVector<T> >
{
    // Public routines
    public:
        static QString fromType();
        static QString fromValue(QVector<T> const &val);
}; // PMsg
// Some definitions

或者使用宏来检测包含的标题:

#if defined(QLIST_H)
template <typename T>
class PMsg<QList<T> >
{
    // Public routines
    public:
        static QString fromType();
        static QString fromValue(QList<T> const &val);
}; // PMsg
// Some definitions
#endif

#if defined(QVECTOR_H)
template <typename T>
class PMsg<QVector<T> >
{
    // Public routines
    public:
        static QString fromType();
        static QString fromValue(QVector<T> const &val);
}; // PMsg
// Some definitions
#endif

我可能最终会包含20多个不同的标题(包括像Eigen那样的非Qt类),或者我可能依赖Qt可以更改的内容,而不会告诉下游开发人员并要求我的同事在此标题之前包含Qt标题肯定的。

我也不确定此时两种方式对编译时间的影响有多大(如果我没有解决这个问题,可能不应该考虑)。

还有其他更好的方法可以解决这个问题,或者我应该遵循哪种方式?

对不起的问题标题表示歉心,感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

根据您的说明,您提供的组件具有自定义点PMsg<T>),可用于添加的组件。您似乎还希望拥有一组已知的组件来利用此自定义。这导致以下推理:

  1. 要使用您的组件,必须包含一个特定的标题(您没有对其进行命名,因此我将使用"pmsg.h")。
  2. 新创建的组件可以并且可能应该在其各自的标头中提供相关的自定义,即,无需在"pmsg.h"中自定义这些组件。
  3. 现有组件(例如QVector<T>)不了解此自定义,并且无法与您的组件集成,需要在"pmsg.h"中声明其自定义。如果不在"pmsg.h"中声明自定义,则除了现有组件的标头之外,所有用户都需要记住还包括声明自定义的标头。假设有一个默认的自定义实现,那不仅会产生意外结果,而且当不同的翻译单元与它们包含的标题不一致时,很容易导致ODR违规。
  4. 对于非模板组件,您可以在"pmsg.h"中转发声明组件以声明自定义,然后在源文件中实现声明,而不实现"pmsg.h"中的声明。也就是说,对于定制的非模板组件,不需要在声明中包含相应的标题,声明就足够了。
  5. 通常,您无法安全地向前声明类模板(主要是因为默认参数只能为第一个声明声明)。此外,您可能需要在标题"pmsg.h"中为模板化自定义提供定义。也就是说,您需要在"pmsg.h"中包含您想要/需要自定义的所有模板类的声明。
  6. tl; dr:如果您想为现有组件提供自定义,您需要在标题中声明它们,并且这样做,您也需要包括它们各自的声明。