我有一个看起来像这样的课程:
// List.hpp
template<typename T>
class List {
...
private:
class Node;
};
我想将List<T>::Node
的完整定义放在一个单独的文件中:
// Node.hpp
template<typename T>
class List<T>::Node {
...
};
我的问题是,我应该在每个文件中包含哪些内容,以及将#include
放在哪里?
最简单的方法(我认为)是在Node.hpp
的末尾添加List.hpp
,而不在Node.hpp
中包含任何内容。但是,这使得Node.hpp
本身不是一个完整的文件(比如说如果我在IDE中打开它,或者由于缺少List<T>
的定义会出现很多错误)。另外,我不确定是否可以将#include
放在文件的底部。
假设每个文件都有自己的包含保护#define
,我还可以在List.hpp
的顶部包含Node.hpp
(以使IDE满意),然后包含Node.hpp
在List.hpp
的底部再次,但我不知道这是不是一个好主意。
答案 0 :(得分:3)
编译List<T>::Node
的成员函数时,编译器始终需要可以看到模板化的类List
。这样做的结果是任何需要查看Node.hpp
内容的编译单元都需要List.hpp
的内容(模板化成员的定义)的可见性。
最简单的选择是将Node.hpp
的内容放在List.hpp
的末尾,并且只在需要任一模板的编译单元中放置#include "List.h"
。这完全消除了Node.hpp
的需要。
如果你真的必须有两个标题(这似乎是任意的,对我来说毫无意义,因为List<T>::Node
是List<T>
的一个组成部分),一个选项是帮助包含警卫。
// List.hpp
#ifndef LIST_HPP_INCLUDED // some unique macro
#define LIST_HPP_INCLUDED
// definition of templated class List
#include "Node.hpp" // this must be after the definition of List<T>
#endif
并在Node.hpp中
// Node.hpp
#ifndef NODE_HPP_INCLUDED // some unique macro
#define NODE_HPP_INCLUDED
#include "List.hpp" // this must precede the definitions for List<T>::Node
// definition of templated class List<T>::Node
#endif
这允许任何编译单元的头部都是#include
d,并且包含守卫会停止无限递归包含。
大多数现代IDE都能应对这种情况。如果你有一个没有,那么只需转换到一个头文件。