当我遇到这个"问题"时,我正在玩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)内。是的未指定这些名称是否首先在全局命名空间范围内声明,然后通过显式使用声明(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>
(尽管不需要)。但为什么全球版本不可用是以前吗?我能不能不期望这种注入是一致的,即使它实际上是同一个头部?这似乎是一种奇怪的行为。注射是否发生可能尚未明确,但至少应该是一种方式或另一种方式,而不是两者都有,对吧?
不要依赖一个标头包括另一个标头,如果您想要在特定标头中声明/定义某些内容,则必须包括它。
对于您给出的例子,对于g++,实际上有两个ptrdiff_t
(和size_t
)的定义。第一个,在namespace std
中,它来自<bits/c++config.h>
。以及来自<stddef.h>
的全局命名空间中的一个(因此也是<cstddef>
)。
问题是您没有使用正确的标头。你应该做
#include <cstddef>
相反。但是您使用
#include<iostream>
它间接地定义了"std::ptrdiff_t"。但是,全局"::ptrdiff_t"并没有在"iostream"中定义,"iostream"也没有像您想象的那样包括"cstdef"。相反,"iostream"确实包含"bits/c++config.h"。实际的"std::ptrdiff_t"在该文件中定义。
如果你查看文件"cstdef"的内容,你会发现那里只有两行"有用"的
顺便说一句,上述讨论适用于GCC 4.6和GCC 4.7。对于GCC 4.4,"iostream"直接包含"cstdef",因此ptrdiff_t将在两个命名空间(std和global)中都可用。#包括#包括
后一行引入了全局"::ptrdiff_t",前一行定义了std名称空间一。