考虑这个翻译单位:
#include <map>
#include <string>
int main()
{
std::map<std::string, std::size_t> mp;
mp.insert(std::make_pair("hello", 42));
}
这个翻译单元有两件事困扰着我,他们是
我刚认为<cstddef>
和<utility>
必须#include
d <string>
和<map>
。
这个假设有多合适?至少对make_pair
我认为有一个非常强大的保证,因为地图成员接口使用std::pair
。对于std::size_t
,没有正式的保证,但只要您加入map
或string
,它就很有可能。第一个风格问题是 您是否会在此翻译单元中明确包含<cstddef>
和<utility>
?
这一部分部分涉及已经包含的一些标题的不确定性。但是,问题的第二部分。假设我们有这个
//f.h
#ifndef BIG_F_GUARD
#define BIG_F_GUARD
#include <string>
std::string f();
#endif
//f.cpp
#include "f.h"
std::string f()
{
std::string s;
return s;
}
第二个问题是: 您是否明确#include <string>
到f.cpp?
我想我的问题很明确。顺便说一句。这两个问题都跟着一个大的WHY
:)谢谢。
答案 0 :(得分:4)
在第一种情况下,我可能不会,但我应该,如果我希望我的代码可以正常移植。 map::size_type
并不要求size_t
,因此<map>
无需包含size_t
的定义。就此而言,size_t
可以是类型别名而不是不同的类型,因此即使size_type
size_t
,也不需要在<map>
使用该名称。正如您所说,<map>
包括<cstddef>
可能但不能保证。
在第二种情况下,我绝对不会,因为我知道我不需要。 IMO .cpp文件有权依赖其相应的.h文件所包含的标头,因为您希望如果修改.h文件,则可能还需要修改.cpp文件 - 更改接口意味着更改它的实施,大部分时间。即使你觉得我没有资格,我总是记录 f.h包括<string>
,在这种情况下我可以依赖它。
关于<utility>
,我不知道<map>
是否允许定义std::pair
(因为它需要它)而没有定义std::make_pair
(来自同一标准)标题,为了论证,我们说不需要定义<map>
)。如果实现的<utility>
版本本身包含一堆其他文件(对于不同的位),并且<map>
只包含它需要的位,那么这是可能的。标题包含其他标题的特定权限,但我不知道是否为标题提供了特定权限,以便将事物放入名称空间std
中,而不包括整个相应的标题。问题是,在实践中很难注意到你在这些情况下忘记了标准包含,因为实现不会检查你,这就是为什么我知道在实践中我很可能不会这样做。幸运的是,对于任何移植到具有不同标头依赖性的实现的人来说应该是任何简单的修复。
答案 1 :(得分:1)
我倾向于做的,并不一定是正确的做法,是包含我需要的所有文件来编译模块。唯一的问题是,当依赖关系发生变化时,最终可能会包含不一定使用的代码。但是,一个好的编译器通常会处理这个问题。
不需要在.cpp文件中包含<string>
,因为它是通过头文件包含的。任何包含的头文件的内容基本上都会“粘贴”到您的cpp文件中。
希望这有帮助!
答案 2 :(得分:1)
答案 3 :(得分:0)
回答你的问题:
包含最少的东西以使其编译,但没有已经实现的过时/附加依赖
答案 4 :(得分:0)
Atleast <map>
被强制包含<utility>
,因为map
的模板如下所示:
namespace std {
template <class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key, T> > >
class map;
}
(标准23.3 / 1)
答案 5 :(得分:0)
我的两位:
main.cpp:我会#include <cstddef>
但可能不是<utility>
。您正在使用std::size_t
,而不管它是否恰好在标准库头中定义。另一方面,请阅读std::map
上的文档,很明显<map>
必须以某种方式定义std :: pair。 #include <utility>
没有理由。 (尤其如此,因为std :: pair之间的连接并且在没有阅读精细文档的情况下有点像WTF。)
f.hh:我会在这里#include <string>
。通常,如果该类仅用作引用,指针或返回类型,则转发声明一个类而不是#include定义该类的头更好。在f.hh中#include <string>
的唯一原因是因为向前声明std::string
有点困难。
f.cpp:我在这里#include <string>
。如果来自f()的返回类型是某个类Foo而不是std :: string,那么期望应该是标题只是前向声明Foo。源文件需要#include指定类Foo的头。返回类型是std :: string不会改变这个基本概念。谁知道?一些迂腐正确的程序员可能会修复f.hh中的问题。 (f.hh的问题在于,#includes <string>
当它真的不需要这样做时。)