条款48:总是#include适当的头文件
STL编程的次要麻烦之一是虽然可以很容易地建立可以在一个平台上编译的软件,但在其它平台上则需要附加的#include指示。这个烦恼来自一个事实:C++标准(不像C标准)未能指定哪一个标准头文件必须或者可能被其他标准头文件#include。由于有了这样的灵活性,不同的实现就会选择去做不同的东西。
这在实践中意味着什么?我可以给你一些的概念。我使用了五个STL平台(咱们叫它们A、B、C、D和E),花了一些时间在它们上测试了一些小程序来看看我可以在忽略哪个标准头文件的情况下仍然成功编译。这间接地告诉我哪个头文件#include了其他的。这是我所发现的:
对于A和C,<vector> #includes <string>.
对于C,<algorithm> #includes <string>.
对于C和D, <iostream> #includes <iterator>.
对于D, <iostream> #includes <string> and <vector>.
对于D和E, <string> #includes <algorithm>.
对于所有的五个实现,<set> #includes <functional>.
除了<set> #include <functional>外,我无法使缺少头文件的程序通过实现B。按照Murphy定律(Murphy's Law),你总是会在像A、C、D或E那样的平台上开发,然后移植到像B那样的平台,尤其是当移植的压力很大而且完成的时间很紧的情况下。(译注:Murphy's Law就是If there are two or more ways to do something, and one of those ways can result in a catastrophe, then someone will do it. (当有两条或更多的路让你抉择,如果其中一条会导致失败,那么你一定会选到它)。经过多年,这一“定律”逐渐进入习语范畴,其内涵被赋予无穷的创意,出现了众多的变体,其中最著名的一条也被称为Finagle's Law(菲纳格定律),具体内容为:If anything can go wrong, it will.(会出错的,终将会出错。)。这一定律被认为是对“墨菲定律”最好的模仿和阐述。)
但是请别指责你将要移植的编译器或库实现。如果你缺少了需要的头文件,这就是你的过错。无论何时你引用了std名字空间里的元素,你就应该对#include合适的头文件负责。如果你遗漏了它们,你的代码也可能编译,但你仍然缺少了必要的头文件,而其他STL平台可能正好会抵制你的代码。
要帮你记起需要的东西,关于在每个标准STL相关的头文件中都有什么,这里有一个快速概要:
几乎所有的容器都在同名的头文件里,比如,vector在<vector>中声明,list在<list>中声明等。例外的是<set>和<map>。<set>声明了set和multiset,<map>声明了map和multimap。
除了四个算法外,所有的算法都在<algorithm>中声明。例外的是accumulate(参见条款37)、inner_product、adjacent_difference和partial_sum。这些算法在<numeric>中声明。
特殊的迭代器,包括istream_iterators和istreambuf_iterators(参见条款29),在<iterator>中声明。
标准仿函数(比如less<T>)和仿函数适配器(比如not1、bind2nd)在<functional>中声明。
无论何时你使用了一个头文件中的任意组件,就要确定提供了相应的#include指示,就算你的开发平台允许你不用它也能通过编译。当你发现移植到一个不同的平台时这么做可以减少压力,你的勤奋将因而得到回报。