C++库命名空间与C Linux函数之间的名称冲突问题

9

Linux中的<ncurses.h>头文件定义了函数meta,而C++元编程库meta将其所有代码放在全局命名空间meta中。

我该如何在同一个C++程序中使用两者(不一定是同一个TU但这会很好)?有没有办法解决名称冲突?

我能想到两种易碎的解决方法,但它们很容易破坏:

  • Workaround A:

     namespace linux {
     #include <ncurses.h>
     }  // namespace linux
     using linux::max_align_t;  // ncurses assumes it is in the global namespace
     #include <meta/meta.hpp>
    

    compiles but will probably fail to link since the ncurses symbols are expected in the global namespace.

  • Workaround B:

    #include <ncurses.h>
    namespace cpp {
    #include <meta/meta.hpp>
    }  // namespace cpp
    

    is very brittle since it will only work as long as the meta library doesn't assume that any of its symbols are in the global namespace. That is, if the library needs to disambiguate internally a symbol and uses ::meta::symbol_name for that, this approach will break.


1
方案A行不通,你自己也知道。方案B可能行得通 - 你可以试试。但我首先会尽力看看是否能够将这两个库分开,以便没有单个翻译单位同时使用两者。 - SergeyA
3
尝试编写一个包装器,这样您就不需要在同一翻译单元中包含两个头文件,并希望链接器可以正常工作。 - nwp
1
请记住,命名空间名称只是编译器的事情。一旦生成了目标文件,就不再存在“命名空间”了。因此,分离翻译单元绝对是正确的方法。这也可能是一个很好的设计决策。 - Some programmer dude
“meta” 库是一个开源的头文件,对吗?那么只改变命名空间名称怎么样? - Barry
1
@Barry 如果该库是一个仅包含头文件的库,或者OP正在从源代码构建该库,那么这将起作用。至少在更新库之前它会起作用。不过,获取所有搜索替换正确可能需要一些工作。 - Some programmer dude
显示剩余3条评论
2个回答

7

我建议使用解决方法C:将您的代码隔离开来,使得meta库和ncurses库在您的项目中处于不同的翻译单元中。这样,在任何一个特定的翻译单元中,不会有一个符号同时被用作命名空间和全局函数。


1
由于meta是一个仅包含头文件的库,因此编写一个围绕<ncurses.h>的包装器可能更容易,该包装器仅在其cpp文件中包含此头文件。 - gnzlbg
@gnzlbg 如果你稍微找一下,我相信已经有可以使用的ncurses库的C++封装器了。 :) - Some programmer dude
2
@JoachimPileborg 不必要: ncurses已经包含了c++绑定 (http://stackoverflow.com/questions/544280/c-wrappers-for-ncurses) - Garf365

1
我相当确定A和B都不会实际起作用,至少不能按照给定的方式。你指向了其中一个,但我认为这是两个问题中较不可能的一个。这里有两个基本上是相互镜像的问题。
如果ncurses中的代码被声明为extern "C"(对于许多已经与C++兼容的C库来说很典型),那么将其包围在命名空间中实际上是行不通的——extern "C"声明基本上忽略命名空间并在全局命名空间中声明函数。命名空间不会改变任何东西,你仍然会遇到冲突。
如果的内容没有声明为extern "C",那么你会遇到你提到的问题:库是使用全局命名空间中的函数构建的,但客户端代码看到的是linux命名空间中代码的定义。由于命名空间影响了编码名称(这就是它如何防止冲突),你的代码将无法链接。所有的linux::*函数都会显示为未解析的外部引用。
为了使这个工作正常运行,您需要确保库代码中没有声明 extern "C",并在头文件(以及库源文件)内指定命名空间,并使用这些声明重新编译库,以便库及其客户端代码就代码所在的命名空间达成一致。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接