我应该在模板类头文件中包含我需要的一切吗?

Should I include everything I need in a template class header file?

本文关键字:包含我 文件 我应该      更新时间:2023-10-16

在编写一个泛型tostring类模板类时,我遇到了一个难题,该模板类为我使用的常见数据结构提供了一个QString代表。我希望我可以在这个头文件中包含最小数量的其他头文件(#include in .h或.c/.cpp?),但也希望它不依赖于它被包含的顺序(头文件顺序)。

基本代码如下:

// 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多个不同的头(包括一些非Qt类,如Eigen),或者我可能依赖于Qt可以改变的东西,而不需要告诉下游开发人员,并要求我的同事在此头之前包括Qt头。

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

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

问题标题不好,谢谢你的帮助

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

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

tl;dr:如果您想为现有组件提供定制,则需要在头文件中声明它们,并且还需要包含它们各自的声明。