处理这个问题的正确方法是以一种不太可能发生名称冲突的方式设置您的构建环境。
编写库的指南
例如,大多数第三方库不会将纯文件引入编译器的包含路径。相反,他们引入了一个包含文件的目录。您可以通过为不同模块引入子目录来增加灵活性。
考虑Boost的目录结构。在顶层,Boost 只为包含搜索路径引入了一个名称:boost
目录。这样,即使boost
引入了许多可能发生冲突的头文件名(如array.hpp
、thread.hpp
或function.hpp
),它们都被包裹在子目录中:
#include <boost/thread.hpp> // this is boost's header
#include "thread.hpp" // some header specific to my current project
// no name clash :)
Boost 附带的不同库使用相同的概念。例如,Boost lockfree 和 Boost assign 都有一个queue.hpp
header。但是它们位于不同的子目录中,因此没有冲突:
#include <boost/lockfree/queue.hpp>
#include <boost/assign/std/queue.hpp> // no clash :)
为了更容易找到正确的头文件,Boost 对包含文件和名称空间使用相同的结构:无锁队列位于boost::lockfree
名称空间中,而分配队列头中的函数则位于boost::assign
. 这样,不仅可以直接从包含文件中找到匹配的命名空间,反之亦然,它还降低了命名空间冲突的可能性,因为命名空间冲突也可能体现在文件层的物理名称冲突中。
您可以根据自己的项目调整这些指南
- 不要将裸包含文件直接引入包含路径。而是将它们组合在一个目录中,以避免使用名称污染包含路径。
- 使用目录树进一步构建单个库中模块的包含文件。
- 尽量使物理结构与逻辑结构相匹配。如果可能,文件系统包含路径应类似于命名空间层次结构。
这首先避免了大多数名称冲突。问题是,如果您必须使用不遵循这些规则的第三方库并且您遇到超出您控制范围的冲突怎么办?
处理第三方库名称冲突的指南
答案是残酷的并通过构建环境强制分离。通过将冲突的库移动到唯一可识别的子目录来重新组织包含路径以解决物理冲突。这通常是非关键的。逻辑冲突需要修补和重新编译,这很不方便。但是,如果您真的在这里遇到名称冲突,这肯定表明至少有一个库供应商没有做好他们的工作,您应该考虑提交一个错误。
远离临时修复,例如#include_next
修复物理冲突或预处理器定义以修复逻辑冲突。他们是肮脏的黑客,虽然他们可能会暂时解决你的问题,但他们很可能最终会回来咬你。