C++风格问题:#include 什么?

发布于 2024-10-04 08:25:09 字数 1165 浏览 0 评论 0原文

考虑这个翻译单元:

#include <map>
#include <string>
int main()
{
   std::map<std::string, std::size_t> mp;
   mp.insert(std::make_pair("hello", 42)); 
}

这个翻译单元中有两件事困扰着我,它们是

  • std::size_t
  • std::make_pair

我刚刚假设 < ;utility> 必须已由 进行 #include 处理。
这个假设有多正确?至少对于 make_pair 来说,我认为有相当强的保证,因为映射成员接口使用 std::pair。对于 std::size_t 没有正式的保证,但只要包含 mapstring ,它仍然很可能可用>。第一个风格问题是您是否会在此翻译单元中明确包含 这部分

部分处理了某些标头已包含的不确定性。然而,还有问题的第二部分。假设我们有

//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 到f.cpp中吗?

我想我已经清楚地表达了我的问题。顺便提一句。这两个问题后面都有一个大的为什么:)谢谢。

consider this translation unit:

#include <map>
#include <string>
int main()
{
   std::map<std::string, std::size_t> mp;
   mp.insert(std::make_pair("hello", 42)); 
}

There are two things in this translation unit that are bothering me, and they are

  • std::size_t
  • std::make_pair

I have just assumed that <cstddef> and <utility> must have been #included by <string> and <map>.
How rightful is this assumption? At least for make_pair I think there's a pretty strong guarantee because map member interfaces use std::pair. For std::size_t there is no formal guarantee but still it is very very very likely that it is available as soon as you include map or string. The stylistic question number one is Would you explicitly include <cstddef> and <utility> in this translation unit?

This part partly deals with the uncertaintly of some header being already included. However, there's the second part of the question. Suppose we have this

//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;
}

Second question is: Would you explicitly #include <string> into f.cpp?

I think I made my question clear. Btw. both questions are followed by a big WHY :) Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

悟红尘 2024-10-11 08:25:09

在第一种情况下,我可能不会,但如果我希望我的代码能够正确移植,我应该这样做。不要求 map::size_typesize_t,因此

无需包含 size_t 的定义。就此而言,size_t 可以是类型别名,而不是不同的类型,因此即使 size_type size_t ,它不需要在

中使用该名称进行定义。正如您所说,很可能但不能保证

包含

在第二种情况下,我绝对不会,因为我知道我不需要。 IMO .cpp 文件有权依赖其相应 .h 文件包含的标头,因为您希望如果修改 .h 文件,您也可能需要修改 .cpp 文件 - 更改接口意味着更改大多数时候它的实施。即使您觉得我没有资格,我也可以随时记录 fh 包含 ,在这种情况下我可以信赖它。

关于,我不知道是否允许

定义std::pair(因为它需要它)而不定义 std::make_pair (来自相同的标准头,为了论证起见,我们假设不需要定义

) 。如果 的实现版本本身包含一堆其他文件(针对不同的位),并且

仅包含它需要的位,则这是可能的。为标头授予了包含其他标头的特定权限,但我不知道是否为标头授予了将内容放入命名空间 std 而不包含整个相应标头的特定权限。问题是,在实践中,很难注意到您忘记了在这些情况下包含的标准,因为实现不会检查您,这就是为什么我知道在实践中我很可能不会这样做。幸运的是,对于移植到具有不同标头依赖项的实现的任何人来说,这应该是任何简单的修复。

In the first case, I probably wouldn't but I should, if I want my code to be properly portable. There's no requirement that map::size_type is size_t, so there's no necessity for <map> to include a definition of size_t. For that matter, size_t can be a type alias rather than a distinct type, so even if size_type is size_t, it needn't have been defined in <map> using that name. So as you say, it's likely but not guaranteed that <map> includes <cstddef>.

In the second case, I definitely wouldn't, because I know I don't need to. IMO a .cpp file is entitled to rely on the headers included by its corresponding .h file, since you kind of expect that if you modify the .h file you potentially need to modify the .cpp file too -- change an interface implies change its implementation, most of the time. And even if you feel I'm not entitled, I can always document that f.h includes <string>, in which case I can rely on that.

Regarding <utility>, I don't know whether <map> is allowed to define std::pair (because it needs it) without defining std::make_pair (which is from the same standard header, and for the sake of argument let's say it isn't needed to define <map>). This would be possible if the implementation's version of <utility> itself includes a bunch of other files, for different bits, and <map> just includes the bit it needs. Specific permission is given for headers to include other headers, but I don't know whether specific permission is given for headers to put things in namespace std without including the whole of the corresponding header. The thing is, in practice it is very difficult to notice that you've forgotten a standard include in these cases, because implementations don't check for you, and that's why I know that in practice I'd quite likely not do it. Luckily it should be any easy fix for anyone porting to an implementation with different header dependencies.

变身佩奇 2024-10-11 08:25:09

我倾向于做的事情(不一定是正确的事情)是包含编译模块所需的所有文件。唯一的问题是,当依赖项发生变化时,您最终可能会得到不一定使用的代码。然而,一个好的编译器通常会处理这个问题。

但是,无需在 .cpp 文件中包含 ,因为它是通过头文件包含的。任何包含的头文件的内容本质上都会“粘贴”到您的 cpp 文件中。

希望这有帮助!

What I tend to do, and it's not necessarily the right thing to do, is to include all the files I need to get the module to compile. The only problem with this is that when dependencies change, you can end up with code included which isn't necessarily used. However a good compiler will normally deal with this.

There's no need to include <string> in your .cpp file however, because it's included through the header file. The contents of any included header files essentially get 'pasted' into your cpp file.

Hope this helps!

失去的东西太少 2024-10-11 08:25:09
  1. 否(只要您知道它必须存在于所有目标平台上;例如 size_t,因为它是字符串内容的参数/返回类型之一)
  2. 否(因为头文件在您的控制之下,并且您知道它已经包含在内)
  1. No (as long as it's something you know it has to be in there on all platforms targeted; e.g. size_t due to it being one of the parameter/return types of string stuff)
  2. No (as the header file is your under your control and you know it's already included)
铜锣湾横着走 2024-10-11 08:25:09

回答您的问题:

包含最少的内容以使其编译,但没有已满足的过时/附加依赖项

To answer your questions:

  1. No
  2. No

Include minimal stuff to make it compile, but no obsolete/additional dependencies that are already fulfilled

┾廆蒐ゝ 2024-10-11 08:25:09

至少

被迫包含 因为 map 的模板如下所示:(

namespace std {
template <class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key, T> > >
class map;
}

标准 23.3/1)

Atleast <map> is forced to include <utility> because the template for map looks like this:

namespace std {
template <class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key, T> > >
class map;
}

(Standard 23.3/1)

糖果控 2024-10-11 08:25:09

我的两点:

  1. main.cpp:我会#include ,但可能不会在这里。您正在使用 std::size_t ,无论它是否恰好在标准库头文件中定义。另一方面,阅读 std::map 的文档,很明显

    必须以某种方式定义 std::pair。没有理由 #include 。 (尤其如此,因为 std::pair 之间的连接 和 之间的连接有点WTF,无需阅读 fine 文档。)

  2. f.hh:我会勉强 #include < ;字符串>在这里。通常,如果类仅用作引用、指针或返回类型,则最好转发声明一个类,而不是 #include 定义该类的标头。在 f.hh 中 #include 的唯一原因是向前声明 std::string 有点困难。

  3. f.cpp:我会在这里#include 。如果 f() 的返回类型是某个类 Foo 而不是 std::string,则预期标头仅向前声明 Foo。源文件需要 #include 指定类 Foo 的标头。返回类型是 std::string 并没有改变这个基本概念。谁知道?一些迂腐正确的程序员可能会解决 f.hh 中的问题。 (f.hh 的问题在于它#includes ,而实际上并不需要这样做。)

My two bits:

  1. main.cpp: I would #include <cstddef> but probably not <utility> here. You are using std::size_t independent of whether it happens to be defined in the standard library headers. On the other hand, read the documentation on std::map and it is very clear that <map> must somehow define std::pair. There's no reason to #include <utility>. (This is particularly so since the connection between std::pair and is a bit of a WTF without reading the fine documentation.)

  2. f.hh: I would grudingly #include <string> here. Normally it is better to forward declare a class rather than #include the header that defines the class if the class is only used as a reference, a pointer, or a return type. The only reason to #include <string> in f.hh is because forward declaring std::string is a bit tough.

  3. f.cpp: I would #include <string> here. If the return type from f() was some class Foo rather than std::string, the expectation should be that the header merely forward declares Foo. The source file needs to #include the header that specifies class Foo. That the return type is std::string doesn't change this basic concept. Who knows? Some pedantically correct programmer might fix the problem in f.hh. (The problem with f.hh being that it #includes <string> when it doesn't really need to do so.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文