模板 (.tpp) 文件包含守卫

Template (.tpp) file include guards

在编写模板 类 时,我喜欢将实现移动到不同的文件 (myclass.tpp) 并将其包含在主 header 的底部 (myclass.hpp).

我的问题是:我是否需要在 .tpp 文件中包含守卫,或者将它们包含在 .hpp 文件中就足够了吗?

示例代码:

myclass.hpp

#ifndef MYCLASS_HPP
#define MYCLASS_HPP

template<typename T>
class MyClass
{
public:
    T foo(T obj);
};

//include template implemetation
#include "myclass.tpp"

#endif

myclass.tpp

#ifndef MYCLASS_TPP //needed?
#define MYCLASS_TPP //needed?

template<typename T>
T MyClass<T>::foo(T obj)
{
    return obj;
}

#endif //needed?

Do I need include guards in the .tpp file or is it sufficient to have them in the .hpp file?

从不 需要 包括守卫:它们非常有用、便宜、无干扰且符合预期。所以是的,你应该用 header guards 来保护这两个文件:

  • 非常有用:它们允许您从多个文件声明依赖关系,而无需跟踪哪些文件已经被包含。
  • 便宜: 这只是一些预编译标记。
  • 无中断:它们非常适合 #include 的大多数用例(我有一个同事不知道如何编写宏,所以他 #included 实现文件 facepalm).
  • 预期:开发人员知道他们是什么,几乎没有注意到他们;相反,缺少头文件包含守卫会唤醒我们并添加到全局 wtf/line 计数器。

我借此机会强调 StoryTeller 的评论:

I'd go a step further and add a descriptive #error directive if the hpp guard is not defined. Just to offer a little protection from people including the tpp first.

这将转换为:

#ifndef MYCLASS_TPP
#define MYCLASS_TPP

#ifndef MYCLASS_HPP
#error __FILE__ should only be included from myclass.hpp.
#endif // MYCLASS_HPP

template<typename T>
T MyClass<T>::foo(T obj)
{
    return obj;
}

#endif // MYCLASS_TPP

注意:如果翻译单元先 #include <myclass.hpp> 然后 #include <myclass.tpp>,则不会触发任何错误,一切正常。

只需在所有头文件中使用 pragma once。编译器将确保您的文件只包含一次。编译器可能只会在非常不合理的情况下无法识别:有人使用 hard-link 构建其包含目录。谁做的?如果有人找不到其文件的唯一名称,为什么他会更熟练地为所有头文件的每个 include guard 找到一个唯一的名称?

另一方面,include guard 可能会被破坏,因为宏的名称将不是唯一的,因为 copy/paste,或者通过首先复制另一个创建的头文件等。 .

如何选择唯一的宏名称<project name>_<filename>?怎么可能比基于整个根目录结构的唯一性更独特呢?

所以最后,在选择 include guard 或 pragma once 时,应该考虑确保唯一性所需的工作成本:

1 - 对于 pragma once 你只需要确保你的系统的目录结构不会因为硬 links 而被弄乱。

2 - 对于 include guard 对于系统上的每个文件,您应该确保宏名称是唯一的。

我的意思是作为一个管理者,评估这份工作的成本和失败的风险确实只有一个选择。 Include guard 仅在不执行评估时使用:这是一个非决定。