代码之家  ›  专栏  ›  技术社区  ›  Dave Mateer

C++命名空间别名和转发声明

  •  9
  • Dave Mateer  · 技术社区  · 15 年前

    我正在使用C++第三方库,将所有的类都放在版本化的命名空间中,我们称之为 tplib_v44 . 它们还定义了通用命名空间别名:

    namespace tplib = tplib_v44;
    

    namespace tplib { class SomeClassInTpLib; }
    

    ... 我在第三方库(稍后将包含在我的.cpp实现文件中)的头上发现编译器错误:

    error C2386: 'tplib' : a symbol with this name already exists in the current scope
    

    [编辑] 供未来观众参考,这里是ICU图书馆。一个解决办法(至少在我的情况下)是在评论接受的答案。

    5 回复  |  直到 15 年前
        1
  •  4
  •   Stephen    15 年前

    看起来有一个丑陋的解决办法,但没有好的解决办法。

    为了 ACE (with a decent explanation) Xerces (with a snarky "this is how c++ works" comment) ,它们定义了可用于“常规”执行此操作的宏。

    ACE_BEGIN_VERSIONED_NAMESPACE_DECL
    class ACE_Reactor;
    ACE_END_VERSIONED_NAMESPACE_DECL
    
    XERCES_CPP_NAMESPACE_BEGIN
    class DOMDocument;
    class DOMElement;
    XERCES_CPP_NAMESPACE_END
    

    tplib 对于这些宏。

    该标准将名称空间和名称空间别名视为不同的东西。你在宣布 tplib公司 作为名称空间,因此当编译器稍后尝试分配别名时,它不能同时是两者,因此编译器会抱怨。

        2
  •  2
  •   Michael Anderson    15 年前

    我认为您的问题是由于tplib是一个别名而不是一个真正的名称空间

    由于版本控制在第三方库中,您可能无法使用它,但是在未版本化的命名空间中使用版本化的命名空间(而不是别名)似乎适用于g++4.0.1和4.1.2。但是我有一种感觉,这是不应该的工作。。。也许还有一些我不知道的问题。

    //This is the versioned namespace
    namespace tplib_v44
    {
       int foo(){ return 1; }
    }
    
    //An unversioned namespace using the versioned one
    namespace tplib
    {
      using namespace tplib_v44;
    }
    
    
    //Since unversioned is a real namespace, not an alias you can add to it normallly.
    namespace tplib
    {
       class Something {};
    }
    
    
    int main()
    {
      //Just to make sure it all works as expected
      tplib::foo();
    }
    
        3
  •  0
  •   AnT stands with Russia    15 年前

    tplib

    很明显,您有一些基于名称空间和名称空间别名的版本控制系统。如果您的类首先是在某个特定的命名空间“版本”中引入的(如44),那么必须在其中声明它。为什么你要把你的类声明推到“回到时间”上 名称空间的过去版本(比如43和30)?你的类在以前的版本中不存在,所以你不应该强制它存在。

        4
  •  0
  •   Mac Umer    15 年前

    编辑:有人指出我没有抓住问题的重点-请不要理会!

    除了在其他答案中突出显示的问题之外,我还有些担心的是,您首先尝试将自己的代码添加到第三方定义的命名空间中。

    名称空间的存在是为了防止冲突符号(类、typdef、枚举等)冲突,将它们放在自己的名称空间中,从而从可能相同的部分限定符号中开发出唯一的完全限定符号。在第三方的命名空间中添加您自己的代码可能会导致问题,例如,在以后的版本中,如果他们决定也要使用相同的符号(比如添加自己的) SomeClassInTpLib std

    完全避免这个问题的一个更安全的解决方案是简单地使用您自己的名称空间。叫它吧 tplib_ex 或者类似的东西和关联仍然会很清楚,但冲突不会是一个问题,你的别名相关的问题也会消失。

        5
  •  0
  •   CoffeDeveloper    8 年前

    阻止您在其命名空间中添加其他内容

    最好的办法是什么?

    没有最好的方法,但尽量避免使用宏,宏是丑陋的,不好看(我不喜欢所有大写的东西)。如果您关心的是“当他们更改版本时会发生什么?”(是的,理论上您必须在所有代码中将“v44”更改为“v45”)

    然后只需使用一个头来向前声明您需要的所有内容。

    #ifdef XXXXXX_TPLIB
       #error "XXXXXX_TPLIB is already taken, change to something else"
    #endif
    #define XXXXXX_TPLIB  tplib_v44 
    //... and that's why I don't like keeping macros around..
    
    namespace XXXXXX_TPLIB
    {
    
        // FORWARD DECLARATIONS
        class A1;
        class A2;
        //...
    }
    namespace tplib = XXXXXX_TPLIB;
    #undef XXXXXX_TPLIB
    

    如果他们更改了库,那么您只需要在一个文件中应用一个更改。许多程序员已经在一个点上保留了前向声明,因为这样更易于管理,而且万一你必须前向声明你保留的很多东西 其他标题更清晰,可读性更高

    #include <TpLibForwards.hpp> // my forwards declarations
    
    推荐文章