2014-09-27 127 views
3

考慮下面的兩段代碼:全球具名命名空間歧義VS嵌套具名命名空間歧義

Snippet A

#include <iostream> 

namespace 
{ 
    bool foo = false; 
} 

bool foo = true; 

int main() 
{ 
    std::cout << foo << std::endl; 
} 

Snippet B

#include <iostream> 

namespace A 
{ 
    namespace 
    { 
     bool foo = false; 
    } 

    bool foo = true; 
} 

int main() 
{ 
    std::cout << A::foo << std::endl; 
} 

Snippet Afoo的用法在方int main()是不明確的,而在Snippet B它不是。爲什麼會這樣?


相關:Anonymous Namespace Ambiguity

+1

A是不合格的查詢; B是合格的查找。不同的規則。 – 2014-09-27 03:40:17

+0

我同意T.C,事實上,如果你簡單地添加'void bar(){std :: cout << foo <<'\ n'; }'命名空間'A'內,但要警告*你添加它是相關的。 [** This Works **](http://ideone.com/azVxvU),例如,[** this not **](http://ideone.com/zt9NPA)。 – WhozCraig 2014-09-27 03:54:52

回答

5

未命名空間的行爲在§7.3.1.1[namespace.unnamed]/P1中指定:

一種無名名稱空間定義表現爲如果它被替換爲

inline_opt namespace unique { /* empty body */ } 
using namespace unique ; 
namespace unique { namespace-body } 

其中inline當且僅當它出現在 未命名名稱空間定義中時,翻譯單元中所有出現的unique都被替換爲相同的標識符,並且此 標識符與整個程序中的所有其他標識符不同。

特別要注意的是,不具名命名空間中的聲明是在周邊範圍內通過使用指示符using namespace unique;可見。

在代碼片段A中,foo是不合格的,所以編譯器執行非限定名稱查找(§3.4.1[basic.lookup.unqual])。這裏相關的是條款的第2款規定:

2從提名的命名空間中的聲明一使用指示符 成爲封閉一個命名空間可見using指令;見 7.3.4。出於在3.4.1中描述的非限定名稱查找規則的目的,來自 使用指令指定的名稱空間的聲明被認爲是該封閉名稱空間的成員。

因此,非限定名稱查找找到foo的兩個聲明,並且名稱不明確。

在片段B中,A::foo是合格的,因此適用合格的名稱查找規則。由於A是一個名稱空間,所以適用的子條款是§3.4.3.2[namespace.qual]。作爲與此有關,該規則在該條款的第2款規定:

對於一個命名空間X和名稱m,命名空間限定查找設置 S(X,m)定義如下:設S'(X,m)是集合所有 的m的聲明X和內聯命名空間集X (7.3.1)。如果S'(X,m)不爲空,則S(X,m)S'(X,m);否則, S(X,m)S(Ni,m)獲提名 所有命名空間Ni通過using指令X其內嵌的命名空間集中的工會。

換句話說,合格的名稱查找認爲通過using指令提名的命名空間只有名字沒有在指定的命名空間和其內嵌的命名空間集中找到。在這裏,名稱foo位於名稱空間A中,因此未考慮使用指令提名的未命名名稱空間,因此不存在歧義。

如果您在代碼片段A中寫入::foo而不是foo,那麼將改爲使用合格的查找規則,而且這將再次成爲不含糊之處。