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与成员发生冲突。)
所以,问题是:
clone()gcc在尝试解析函数调用时丢弃我的版本是否正确::clone(daughter)?clone()在上面的示例中,我可以在不重命名函数(或匿名命名空间)但仍然包含 的情况下解决问题吗<thread>?
- 当尝试解析函数调用 ::clone(daughter) 时,gcc 是否正确地放弃我的clone() 版本?
是的,我想是这样。
- 这种方式对全局命名空间的污染是否符合标准?
这是有争议的。对于纯 C++ 实现来说,没有,但数量并不多。实际上,大多数是“POSIX 上的 C++”或“Windows 上的 C++”实现,并声明了许多 C++ 标准中没有的名称。
命名空间污染问题是众所周知的(11196、51749等),没有简单的解决方案。
问题是大多数 C++ 标准库实现不控制 C 库,而只包含平台的本机 C 头文件,这些头文件会引入其他名称。
- 在上面的示例中,我可以在不重命名clone()函数(或匿名命名空间)但仍然包含 的情况下解决问题吗?
在您的特定情况下,您可以通过将clone重载放入全局命名空间中来解决名称查找问题,以便查找与函数同时找到它<sched.h>,并使其静态以再次为其提供内部链接。