代码之家  ›  专栏  ›  技术社区  ›  Armen Tsirunyan

C++风格问题:包括什么?[副本]

  •  9
  • Armen Tsirunyan  · 技术社区  · 14 年前

    考虑一下这个翻译单元:

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

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

    • 标准:尺寸
    • 标准:制造对

    我只是假设 <cstddef> <utility> 一定是 #include <string> <map> .
    这种假设有多正当?至少是为了 make_pair 我认为有很强的保证,因为映射成员接口使用 std::pair . 为了 std::size_t 虽然没有正式的保证,但很有可能只要你包括 map string . 第一个文体问题是 你会明确地包括 <cstddef> <效用> 在这个翻译单元里?

    这一部分处理的是某些标题已经包含的不确定性。然而,问题的第二部分。假设我们有这个

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

    第二个问题是: 你能明确地包括 <字符串> 加入f.cpp?

    我想我把问题说清楚了。顺便说一句,两个问题后面都有一个大问题 WHY :)谢谢。

    6 回复  |  直到 14 年前
        1
  •  4
  •   Steve Jessop    14 年前

    在第一种情况下,我可能不会,但我应该,如果我想我的代码是适当的可移植性。没有要求 map::size_type size_t ,所以没有必要 <map> 包括 尺寸 . 就这点而言, 尺寸 可以是类型别名,而不是不同的类型,因此即使 size_type 尺寸 ,不必在 <地图> 用那个名字。所以正如你所说,很可能但不能保证 <地图> 包括 <cstddef> .

    在第二种情况下,我绝对不会,因为我 知道 我不需要。IMOA.cpp文件有权依赖其对应的.h文件所包含的头,因为您可能希望,如果修改.h文件,您也可能需要修改.cpp文件--更改接口意味着更改其实现,大多数情况下。即使你觉得我没有资格 文件 f.h包括 <string> ,在这种情况下,我可以相信。

    关于 <utility> ,我不知道 <地图> 允许定义 std::pair (因为它需要它)没有定义 std::make_pair (它来自同一个标准头,为了便于讨论,假设不需要定义 <地图> ). 如果实现的版本 <效用> 它本身包含一堆其他文件,用于不同的位,并且 <地图> 只包括它需要的那一点。为头提供了包含其他头的特定权限,但我不知道是否为头提供了将内容放入命名空间的特定权限 std 不包括整个对应的头。问题是,在实践中很难注意到,在这些情况下,您忘记了标准include,因为实现不会检查您,这就是为什么我知道,在实践中,我很可能不会这样做。幸运的是,对于任何移植到具有不同头依赖项的实现的人来说,这应该是一个简单的解决方案。

        2
  •  1
  •   Nick    14 年前

    我倾向于做的,也不一定是正确的事情,就是包含所有需要编译模块的文件。唯一的问题是,当依赖关系发生变化时,最终可能会出现不一定要使用的代码。但是一个好的编译器通常会处理这个问题。

    没有必要包括 <string> 但是在.cpp文件中,因为它包含在头文件中。任何包含的头文件的内容实际上都被“粘贴”到cpp文件中。

    希望这有帮助!

        3
  •  1
  •   Mario    14 年前
    1. 不(只要你知道它必须存在于所有目标平台上;例如size_t,因为它是字符串的参数/返回类型之一)
    2. 不(因为头文件在您的控制之下,并且您知道它已经包含在内)
        4
  •  0
  •   graham.reeds    14 年前

    回答你的问题:

    包含使其编译的最少内容,但不包含已完成的过时/附加依赖项

        5
  •  0
  •   Andreas Brinck    14 年前

    至少 <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)

        6
  •  0
  •   David Hammen    14 年前

    我的两部分:

    1. main.cpp:我会包括 <cstddef> 但可能不是 <utility> 在这里。你在用 std::size_t 与是否在标准库头中定义无关。另一方面,请阅读 std::map 很明显 <map> 必须以某种方式定义std::pair。没有理由包括 <效用> . (这尤其如此,因为std::pair和之间的连接有点像WTF,而没有读取 好的 文档。)

    2. f.hh:我会勉强地包括 <string> 在这里。通常,如果类仅用作引用、指针或返回类型,则转发声明类比包含定义该类的头更好。唯一的理由是 <字符串> 在f.hh中是因为forward声明 std::string 有点难。

    3. f.cpp:我会包括 <字符串> 在这里。如果f()的返回类型是某个类Foo,而不是std::string,则期望头只向前声明Foo。源文件需要包含指定类Foo的头。返回类型是std::string并没有改变这个基本概念。谁知道呢?一些学究式的程序员可能会在f.hh中解决这个问题。(f.hh的问题在于它包括 <字符串> 当它不需要这么做的时候。)

    推荐文章