Answers:
我认为没有推荐的顺序,只要可以编译即可!令人讨厌的是,当某些标头要求首先包含其他标头时...这是标头本身的问题,而不是包含顺序的问题。
我个人的喜好是从本地到全局,每个小节都按字母顺序排列,即:
我对1.的理由是,它应证明每个标头(为此有一个cpp)都可以在#include
没有先决条件的情况下使用d(terminus technicus:标头是“独立的”)。其余的似乎只是从逻辑上流向那里。
要记住的一件大事是,您的标头不应依赖于其他标头被首先包含。确保这一点的一种方法是在其他任何标题之前包含标题。
“使用C ++进行思考”特别提到了Lakos的“大型C ++软件设计”:
通过确保组件的.h文件本身可以进行解析-无需外部提供的声明或定义,可以避免潜在的使用错误。包括.h文件作为.c文件的第一行,可以确保没有关键内容.h文件中缺少组件物理接口固有的信息(或者,如果存在,则在尝试编译.c文件时会立即找到它)。
也就是说,按以下顺序包括:
如果任何标题在按此顺序包含时有问题,请修复它们(如果使用的话)或不使用它们。抵制不写干净标题的库。
Google的C ++风格指南提出了几乎相反的说法,实际上根本没有道理。我个人倾向于拉科斯的方法。
我遵循两个简单的规则来避免绝大多数问题:
我还遵循以下准则:
换一种说法:
#include <stdio.h>
#include <string.h>
#include "btree.h"
#include "collect_hash.h"
#include "collect_arraylist.h"
#include "globals.h"
虽然作为准则,但这是主观的。另一方面,我严格执行这些规则,甚至在某些令人讨厌的第三方开发人员不认同我的愿景的情况下,甚至为“包装”头文件提供包含保护和分组包含的观点:-)
在墙上添加我自己的砖块。
所以我通常是这样的:
// myproject/src/example.cpp
#include "myproject/example.h"
#include <algorithm>
#include <set>
#include <vector>
#include <3rdparty/foo.h>
#include <3rdparty/bar.h>
#include "myproject/another.h"
#include "myproject/specific/bla.h"
#include "detail/impl.h"
每一组与下一组用空白行分隔:
还要注意,除了系统头文件之外,每个文件都位于一个具有名称空间名称的文件夹中,这是因为这样更容易跟踪它们。
#define
利于弄乱其他代码),并防止隐式依赖。例如,如果我们的代码库头文件foo.h
确实依赖<map>
于.cc
文件,但它在文件中使用的所有地方都<map>
已经包含在内,我们可能不会注意到。直到有人试图包含foo.h
而不首先包含<map>
。然后他们会很生气。
.h
问题至少都有一个.cpp
首先包含它(实际上,在我的个人代码中,关联的单元测试首先包含它,而源代码将其包含在其合法组中) )。关于不受影响,如果任何头文件包括<map>
在内,那么以后包含的所有头文件都会受到影响,因此对我来说似乎是一场失败的战斗。
Header corresponding to this cpp file first (sanity check)
。如果#include "myproject/example.h"
将所有内容移到所有内容的末尾,有什么特别的地方吗?
我建议:
当然,如有可能,请在每个部分中按字母顺序排列。
始终使用前向声明以避免#include
头文件中不必要的。
我敢肯定,在理智的世界中,在任何地方都不推荐这样做,但是我希望按名称长度将系统包括在内,并按相同的长度按词法排序。像这样:
#include <set>
#include <vector>
#include <algorithm>
#include <functional>
我认为,在其他人之前包含您自己的标头是一个好主意,以避免包含顺序依赖的可耻性。
windows.h
。
首先包含与.cpp ...对应的标题,换句话说,source1.cpp
应source1.h
在包含其他任何内容之前包含。我能想到的唯一例外是将MSVC与预编译头一起使用时,在这种情况下,您不得不stdafx.h
其他内容。
推理:source1.h
在所有其他文件之前包含之前,确保了它可以独立存在而没有依赖性。如果以后source1.h
需要依赖,编译器会立即提醒您将必需的前向声明添加到中source1.h
。反过来,这确保了标头可以被其依赖者以任何顺序包括在内。
例:
source1.h
class Class1 {
Class2 c2; // a dependency which has not been forward declared
};
source1.cpp
#include "source1.h" // now compiler will alert you saying that Class2 is undefined
// so you can forward declare Class2 within source1.h
...
MSVC用户:我强烈建议使用预编译头。因此,将#include
标准标头(以及其他永远不会更改的标头)的所有伪指令移动到stdafx.h
。
在C / C ++世界中,这是一个棘手的问题,它包含许多超出标准的元素。
我认为只要编译头文件顺序就不会是一个严重的问题,就像squelart所说的那样。
我的想法是:如果所有这些标头中都没有符号冲突,则任何顺序都可以,并且标头依赖性问题可以在以后通过向有缺陷的.h中添加#include行来解决。
当某些标头根据上面的标头更改其动作(通过检查#if条件)时,才出现真正的麻烦。
例如,在VS2005的stddef.h中,有:
#ifdef _WIN64
#define offsetof(s,m) (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
现在的问题是:如果我有一个需要与许多编译器一起使用的自定义标头(“ custom.h”),包括一些未offsetof
在其系统标头中提供的较旧的编译器,则应在标头中编写:
#ifndef offsetof
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
而且一定要在用户告诉#include "custom.h"
以后的所有系统头,否则,线offsetof
在STDDEF.H将断言宏重新定义错误。
我们祈祷在职业生涯中不再遇到此类情况。