当我遇到这个“问题”时,我正在玩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>
(尽管不需要)。但是为什么全球版本也没有
以前?即使它实际上是相同的标题,我能不能指望这种注射是一致的吗?这似乎很奇怪。注射是否发生可能是未指定的,但至少应该是这样或那样,而不是两者,对吗?
答案 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名称空间。