C库设施标头的命名空间注入不一致

时间:2012-09-24 23:49:49

标签: c++ c++11 standards header-files c++-standard-library

当我遇到这个“问题”时,我正在玩ptrdiff_t并阅读C ++ 11标准。首先,事实:

类型ptrdiff_t(仅作为示例)从标准C库标题<stddef.h>提取到<cstddef>(第18.2 / 2节)。第17.6.1.2节告诉我们从C标准库中提取的声明将在std命名空间内:

  

但是,在C ++标准库中,声明(在C中定义为宏的名称除外)在命名空间std的命名空间范围(3.3.6)内。它是   未指定是否首先在全局命名空间范围内声明这些名称,然后通过显式 using-declarations (7.3.3)将其注入命名空间std

正如它所说,声明可能先在全局命名空间中声明,然后注入std。因此,对于我的实现来说,以下编译就好了:

#include <cstddef>

int main(int argc, const char* argv[])
{
  std::ptrdiff_t x;
  ptrdiff_t y;
  return 0;
}

我的实现(gcc 4.6.3)必须在全局命名空间中声明ptrdiff_t,然后将其注入std。但是,如果我编译以下代码,则会收到错误(请注意<iostream>包含):

#include <iostream>

int main(int argc, const char* argv[])
{
  std::ptrdiff_t x;
  ptrdiff_t y;
  return 0;
}
  

main.cpp:在函数'int main(int,const char **)'中:
  main.cpp:6:3:错误:'ptrdiff_t'未在此范围内声明
  main.cpp:6:3:注意:建议的替代方案:
  /usr/include/c++/4.6/i686-linux-gnu/./bits/c++config.h:156:28:注意:'std :: ptrdiff_t'

因此,由于std::ptrdiff_t可用,<iostream>必须以某种方式包含<cstddef>(尽管不需要)。但是为什么全球版本也没有 以前?即使它实际上是相同的标题,我能不能指望这种注射是一致的吗?这似乎很奇怪。注射是否发生可能是未指定的,但至少应该是这样或那样,而不是两者,对吗?

2 个答案:

答案 0 :(得分:3)

不要依赖一个包含另一个标题的标题,如果你想要在特定标题中声明/定义的内容,那么你必须包含它。

对于您提供的示例,使用g ++实际上有两个ptrdiff_t(和size_t的定义)。第一个是namespace std,来自<bits/c++config.h>。来自<stddef.h>(以及<cstddef>)的全局命名空间中的那个。

答案 1 :(得分:1)

问题是您没有使用正确的标头。你应该做

     #include <cstddef>

代替。但是你使用

        #include<iostream>

它间接地定义了“std :: ptrdiff_t”。但是,全局“:: ptrdiff_t”未在“iostream”中定义,“iostream”未包含“cstddef”,如您所想。相反,“iostream”确实包含“bits / c ++ config.h”。实际的“std :: ptrdiff_t”在该文件中定义。

如果查看文件“cstddef”的内容,你会发现那里只有两条“有用”的行

BTW,上述讨论适用于GCC 4.6和GCC 4.7。对于GCC 4.4,“iostream”直接包含“cstddef”,因此ptrdiff_t将在两个名称空间(std和global)中可用。         #包括         #include

后一行引入了全局“:: ptrdiff_t”,前者定义了std名称空间。