标准头文件对全局命名空间的污染

Wal*_*ter 3 c++ namespaces standards-compliance language-lawyer

我一次又一次地遇到由于从 C++ 标准头文件间接包含 C 头文件而导致的命名空间污染问题。例如,在我的 Linux 系统上,gcc(版本 5.1.1)<thread>包含usr/include/bits/sched.h,它声明

extern "C" {
  extern int clone(int (*__fn) (void *__arg), void *__child_stack, int __flags, void *__arg, ...) throw();
}
Run Code Online (Sandbox Code Playgroud)

在下面的最小示例中

#include <thread>                              // indirect inclusion of <sched.h>

namespace {
  struct foo
  { virtual foo*clone() const=0; };

  foo*clone(std::unique_ptr<foo> const&);      // function intended

  struct bar : foo
  {
    std::unique_ptr<foo> daughter;
    bar(foo*d) : daughter(d) {}
    foo*clone() const
    { return new bar(::clone(daughter)); }     // to be called here
  };
}
Run Code Online (Sandbox Code Playgroud)

编译器抱怨调用::clone()与定义不匹配bits/sched.h(忽略之前的定义)。(请注意,只是简单地调用clone而不是::clone与成员发生冲突。)

所以,问题是:

  1. clone()gcc在尝试解析函数调用时丢弃我的版本是否正确::clone(daughter)
  2. 这种方式对全局命名空间的污染是否符合标准?
  3. clone()在上面的示例中,我可以在不重命名函数(或匿名命名空间)但仍然包含 的情况下解决问题吗<thread>

Jon*_*ely 5

  1. 当尝试解析函数调用 ::clone(daughter) 时,gcc 是否正确地放弃我的clone() 版本?

是的,我想是这样。

  1. 这种方式对全局命名空间的污染是否符合标准?

这是有争议的。对于纯 C++ 实现来说,没有,但数量并不多。实际上,大多数是“POSIX 上的 C++”或“Windows 上的 C++”实现,并声明了许多 C++ 标准中没有的名称。

命名空间污染问题是众所周知的(11196、51749),没有简单的解决方案

问题是大多数 C++ 标准库实现不控制 C 库,而只包含平台的本机 C 头文件,这些头文件会引入其他名称。

  1. 在上面的示例中,我可以在不重命名clone()函数(或匿名命名空间)但仍然包含 的情况下解决问题吗?

在您的特定情况下,您可以通过将clone重载放入全局命名空间中来解决名称查找问题,以便查找与函数同时找到它<sched.h>,并使其静态以再次为其提供内部链接。