【问题标题】:Inconsistent namespace injection for C library facilities headersC 库设施标头的命名空间注入不一致
【发布时间】:2012-09-24 23:49:49
【问题描述】:

当我遇到这个“问题”时,我正在使用 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。但是,如果我编译以下代码,我会收到一个错误(注意 &lt;iostream&gt; 包含):

#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 可用,&lt;iostream&gt; 必须以某种方式包含&lt;cstddef&gt;(尽管不是必需的)。但是为什么全球版本不可用 以前是?即使它实际上是相同的标头,我是否不能期望这种注入是一致的?这似乎是奇怪的行为。是否发生注入可能未指定,但至少应该是一种方式或另一种方式,而不是两者,对吧?

【问题讨论】:

  • 未指定表示未指定。谁说没有在命名空间std 中直接声明所有typedef 的标头,那么cstdlib 既包括stdlib.h 又包括标头? (大概在这种情况下,cstddef 包含 stddef.h 以避免错误地使用全局命名空间中的类型来破坏代码,而 iostream 仅包含上述标头而不是 cstddef 以避免污染全局命名空间。)
  • 为什么不只包括 cstddef?
  • @ildjarn 也许吧。我认为您的想法不符合cstddef 必须在std 中声明或全局声明并注入std 的要求。在您的示例中,所有内容都将在两个命名空间中单独声明。我可能太接近标准的具体程度了。
  • @asd 当然,我通常会这样做。这只是我遇到的我想知道的事情。
  • @sftrabbit :你在哪里看到这个要求?除了“声明在命名空间std 的命名空间范围内”之外,该标准没有说明任何具体内容。同样,未指定使用什么机制来实现这一点。

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


【解决方案1】:

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

对于您给出的示例,使用 g++ 实际上有两个定义 ptrdiff_t (和 size_t 就此而言)。第一个,在namespace std,来自&lt;bits/c++config.h&gt;。还有来自&lt;stddef.h&gt;(以及&lt;cstddef&gt;)的全局命名空间中的那个。

【讨论】:

    【解决方案2】:

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

         #include <cstddef>
    

    相反。不管你怎么用

            #include<iostream>
    

    其中间接定义了“std::ptrdiff_t”。但是,全局“::ptrdiff_t”没有在“iostream”中定义,并且“iostream”没有像您想象的那样包含“cstddef”。相反,“iostream”确实包含“bits/c++config.h”。实际的“std::ptrdiff_t”在该文件中定义。

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

    顺便说一句,以上讨论适用于 GCC 4.6 和 GCC 4.7。对于 GCC 4.4,“iostream”间接包含“cstddef”,因此 ptrdiff_t 在两个命名空间(std 和全局)中都可用。 #包括 #包括

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-06
      • 2019-07-22
      • 1970-01-01
      • 2016-06-11
      • 2020-02-04
      • 1970-01-01
      • 2010-11-04
      相关资源
      最近更新 更多