簡體   English   中英

C ++命名空間別名和轉發聲明

[英]C++ namespace alias and forward declaration

我正在使用一個C ++第三方庫,它將所有類放在一個版本化的命名空間中,我們稱之為tplib_v44 它們還定義了通用名稱空間別名:

namespace tplib = tplib_v44;

如果使用通用命名空間在我自己的.h文件中正向聲明庫的成員...

namespace tplib { class SomeClassInTpLib; }

...我在第三方庫的頭文件中遇到編譯器錯誤(稍后將在我的.cpp實現文件中包含):

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

如果我使用特定於版本的命名空間,那么一切正常,但那么......重點是什么? 處理這個問題的最佳方法是什么?

[編輯]僅供未來觀眾使用,這是ICU圖書館。 解決方案(至少在我的情況下)是對已接受答案的評論。

看起來這有一個丑陋的解決方法,但沒有好的解決方案。

對於ACE(有一個不錯的解釋)Xerces(有一個諷刺的“這就是c ++的工作方式”評論) ,他們定義了你可以用來“泛化”的宏。

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

它看起來像一個不幸的c ++工件,嘗試在你的tplib搜索這些宏。

該標准將名稱空間和名稱空間別名視為不同的東西。 您將tplib聲明為命名空間,因此當編譯器稍后嘗試分配別名時,它不能同時為兩者,因此編譯器會抱怨。

我認為你的問題是由於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();
}

呃......你所說的對我來說是倒退的。 恰恰相反,嘗試將您的類聲明為tplib命名空間的成員有什么tplib (忘記它甚至不是命名空間,而是命名空間別名,這就是你得到錯誤的原因。)

很明顯,你有一些基於命名空間和命名空間別名的版本控制系統。 如果您的類首先在命名空間的某個特定“版本”中引入(如44) - 那就是它必須聲明的命名空間。為什么要嘗試“及時”推送您的類聲明,即所有以前的版本命名空間(如43,比方說30)? 您的類在以前的版本中不存在,因此您不應該強制它在那里。

編輯:我已經指出我錯過了問題的重點 - 請隨意忽略!

除了其他答案中突出顯示的問題外,它還讓我擔心您首先嘗試將自己的代碼添加到第三方定義的命名空間。

存在命名空間以防止沖突的符號(類,typdef,枚舉等)發生沖突,將它們放在它們自己的命名空間中,從而從可能相同的部分限定符號開發一個唯一的完全限定符號。 將您自己的代碼添加到第三方的命名空間可能會導致問題,如果(例如)在更高版本中他們認為他們也想要使用相同的符號(比如添加他們自己的SomeClassInTpLib ) - 突然之間,命名沖突命名空間意味着防止將他們丑陋的頭部。 這就是為什么添加到std命名空間通常是不好的做法。

一個更安全的避免問題的解決方案就是簡單地使用您自己的命名空間。 稱之為tplib_ex或類似的東西,關聯仍然是明確的,但沖突不會成為問題,你的別名相關問題也將消失。

重點是什么?

阻止你在命名空間中添加額外的東西 ,可能是因為他們認為很快就會添加更多的名字(而且他們使用的是版本化命名空間可能會暗示這一點)。 然而,這些只是推測。 這有一個副作用,就是阻止你認為更合理的命名空間中的前向聲明,所以我認為這只是糟糕的編程習慣。

處理這個問題的最佳方法是什么?

沒有最好的方法,但盡量避免使用宏,宏是丑陋的,不好看(我不喜歡所有那些大寫的東西)。 如果你擔心的是“當他們改變版本時會發生什么?” (是的,理論上你必須在你的所有代碼中將“v44”更改為“v45”)

然后只需使用1個單頭來轉發聲明你需要的一切。

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個文件中。 許多程序員已經在一個點上保留了前向聲明,因為它更易於管理,並且如果你必須轉發聲明大量的東西,你可以保持其他標題更清晰,更可讀

#include <TpLibForwards.hpp> // my forwards declarations

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM