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

Inconsistent namespace injection for C library facilities headers

本文关键字:命名空间 注入 不一致 设施      更新时间:2023-10-16

当我遇到这个"问题"时,我正在玩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名称空间一。