模板 (.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
的大多数用例(我有一个同事不知道如何编写宏,所以他 #include
d 实现文件 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 仅在不执行评估时使用:这是一个非决定。
在编写模板 类 时,我喜欢将实现移动到不同的文件 (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
的大多数用例(我有一个同事不知道如何编写宏,所以他#include
d 实现文件 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 仅在不执行评估时使用:这是一个非决定。