C++;命名空间别名和转发声明 我使用C++第三方库,将所有的类都放在版本化的命名空间中,我们称之为代码> TPLBIV44()。它们还定义了通用命名空间别名: namespace tplib = tplib_v44;

C++;命名空间别名和转发声明 我使用C++第三方库,将所有的类都放在版本化的命名空间中,我们称之为代码> TPLBIV44()。它们还定义了通用命名空间别名: namespace tplib = tplib_v44;,c++,namespaces,forward-declaration,C++,Namespaces,Forward Declaration,如果转发使用泛型命名空间在我自己的.h文件中声明库的成员 namespace tplib { class SomeClassInTpLib; } 。。。我在第三方库(稍后将包含在我的.cpp实现文件中)的头上发现编译器错误: 如果我使用特定于版本的名称空间,那么一切正常,但是。。。重点是什么?处理这个问题的最好方法是什么 [编辑]供未来观众参考,这是ICU图书馆。一个解决方案(至少在我的情况下)出现在对已接受答案的评论中。似乎有一个丑陋的解决方法,但没有好的解决方案 对于和,它们定义了可用于“

如果转发使用泛型命名空间在我自己的.h文件中声明库的成员

namespace tplib { class SomeClassInTpLib; }
。。。我在第三方库(稍后将包含在我的.cpp实现文件中)的头上发现编译器错误:

如果我使用特定于版本的名称空间,那么一切正常,但是。。。重点是什么?处理这个问题的最好方法是什么


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

似乎有一个丑陋的解决方法,但没有好的解决方案

对于和,它们定义了可用于“一般”执行此操作的宏

它看起来像是一个不幸的C++工件,尝试在你的代码> TPLIB < /COD>中搜索这些宏。


该标准将名称空间和名称空间别名视为不同的东西。您正在将
tplib
声明为命名空间,因此当编译器稍后尝试分配别名时,它不能同时为这两个别名,因此编译器会抱怨。

Er。。。你说的话在我看来是背道而驰的。恰恰相反,将类声明为
tplib
名称空间的成员有什么意义?(暂时忘记它甚至不是一个名称空间,而是一个名称空间别名,这就是为什么会出现错误。)


很明显,您有一些基于名称空间和名称空间别名构建的版本控制系统。如果您的类首先在某个特定的名称空间“版本”中引入(如44),则必须在该名称空间中声明。为什么您试图将您的类声明“推回到时间”,即推到名称空间的所有以前版本中(比如43和30)?您的类在以前的版本中不存在,因此您不应该将其强制存在。

我认为您的问题是由于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();
}

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

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

名称空间的存在是为了防止冲突符号(类、typedef、枚举等)的冲突,将它们放在它们自己的名称空间中,从而从可能相同的部分限定符号中开发出唯一的完全限定符号。如果(例如)在更高版本中,第三方决定使用相同的符号(例如添加自己的
SomeClassInTpLib
),则将自己的代码添加到第三方的命名空间可能会导致问题-突然之间,命名空间旨在防止的命名冲突会让他们头痛不已。这就是为什么添加到
std
名称空间通常是不好的做法

完全避免这个问题的更安全的解决方案是只使用您自己的名称空间。称之为
tplib_ex
或类似的名称,关联仍然很清楚,但冲突不会成为问题,与别名相关的问题也将消失

重点是什么

阻止您在他们的命名空间中添加其他内容,可能是因为他们认为很快会添加更多的名称(事实上,他们正在使用版本化的命名空间可能表明这一点)。然而,这些只是猜测。这样做的副作用是防止在您认为更合理的名称空间中进行前向声明,因此我认为这只是他们的糟糕编程实践

处理这个问题的最好方法是什么

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

然后只需使用一个标题就可以向前声明所需的所有内容

TpLibForwards.hpp

#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
如果他们更改了库,那么您只需要在1个文件中应用1个更改和1个。许多程序员已经在某一点上保留了前向声明,因为这更易于管理,而且如果您必须前向声明大量内容,则会使其他标题更干净、可读性更强

#include <TpLibForwards.hpp> // my forwards declarations
#包括//我的声明

他没有向库中添加符号,而是试图向前声明已存在于第三方命名空间(别名)中的对象。请注意,如果已在版本化命名空间中声明了
某些内容,则这不会引发错误。它将静默地接受并且
tplib::Something
将引用版本化的,忽略
tplib::Something
。此外,ADL将不适用于以
Something
作为参数的调用-版本化名称空间将不会查找候选名称。@Johannes-听起来很合理。你能举个例子说明ADL是如何在用例而不是直接命名空间中失败的吗?我想我最初的问题并不清楚。命名空间别名由第三方开发人员提供,因此我可以将它们的类称为
tplib::SomeClass
。他们在内部使用版本化名称空间。因此,在下一个版本中,内部名称空间可能是
tplib_v50
。但是我不必检查所有的文件并将
tplib\u v44::
更改为#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