2014-10-02 27 views
3

在下面的代碼片段中,我可以理解(從§3.3.2/ 6第二個要點),聲明struct B* p;中的名稱B作爲的類名稱被注入到全局名稱空間中。我對§3.3.2/ 6中的'first'這個詞的解釋是否正確?

struct A { 
// struct B{}; 
    int B; 
    struct B* p; 
}; 

void f(B&) {} 

int main() 
{ 
    A a; 
    f(*a.p); 
} 

§3.3.2/ 6:

一類第一聲明的聲明的點闡述型說明符如下:

  • 申請表格

    class-keyattribute-specifier-seqoptidentifier;

    標識符被聲明爲在 包含聲明的範圍類名,否則

  • 用於闡述型說明符形式的

    class-key標識符

    如果詳細制定型說明符DECL說明符-SEQ參數聲明子句中的命名空間範圍內定義的函數的中所使用的,標識符被聲明爲 類名在包含聲明的名稱空間中;否則,除了作爲的朋友聲明,標識符是 聲明在包含 聲明的最小名稱空間或塊範圍內。 [注意:這些規則也適用於模板。 - 年底 注] [:中其他形式闡述類型說明符不 宣佈一個新的名稱,因此必須引用現有的類型名稱。 見3.4.4和7.1.6.3。 - 注完]

但是,如果我去掉裏面struct A的的struct B{};定義,我剛纔對於注射名字B到全局命名空間中說,已經不發生,如代碼不能編譯。我認爲這需要做上面的字第一(重點煤礦),因爲現在類名B,在申報struct B* p;不再是它的第一個聲明在其聲明區。我正確地說這個嗎?

假設我的解釋是正確的,爲什麼在這種情況下類名B沒有注入到全局名稱空間中?請注意,在這種情況下,嵌套類struct B{};將隱藏在A內部,即,即使我們將函數f的聲明更改爲void f(A::B&),代碼也不會編譯。

還有一點我不清楚:是什麼讓實現者決定將類名注入命名空間,或者在第二個項目符號中包含詳細類型說明符的塊範圍點以上?也就是說,他們爲什麼不把類名聲明留在類範圍內?

+3

注入封閉名稱空間肯定是爲了與C兼容。 – avakar 2014-10-02 20:01:28

+0

您可以多探索一下嗎? – 2014-10-02 20:07:05

+0

C沒有類/結構作用域,因此,struct S {struct X {int y; }; int x; }; struct X my_var = {42};'在C中是合法的(呃,它很醜 - 但它實際上是用clang和gcc編譯的,儘管後者有一個警告)。 – dyp 2014-10-02 20:19:12

回答

2

你是正確的,即在§3.3.2/ 6第一關鍵字也是以下原因:

struct A { 
    struct B *p; 
    struct B{}; 
    int b; 
}; 

void f(B* arg) { 
    std::cout << std::is_same<decltype(arg), A::B*>::value; // not the same type 
} 

int main() 
{ 
    A a; 
    f(a.p); 
} 

爲什麼它的類名B沒有注入在這種情況下在全局命名空間?

作爲DYP指出的那樣,[basic.lookup.elab]/2解釋3.3.2僅在殼體進行沒有先前的聲明可能被發現

如果闡述型-specifier由類密鑰和 此查找沒有找到之前聲明的類型名稱推出,或者如果 闡述型符出現與形式的聲明:

類的關鍵字屬性符-seqopt標識符;

闡述型說明符是介紹如在3.3.2.the

描述最後,我找到了這種行爲可能是從C99 6.7.2繼承的 類名的聲明。3/P8

如果表單的類型說明符

結構-或癒合標識符

發生不是作爲上述形式之一的一部分 其他,和的沒有其它聲明 標識符作爲標籤是可見的,則它聲明不完整的 結構或聯合類型,並將該標識符聲明爲該類型的標籤 .113)

113)類似的結構與枚舉不存在。

+0

非常好的答案,但我相信上面的@dyp給出的例子更能說明與3.3.2/6(+1)中第二個要點提出的類名注入相關的C兼容性。 – 2014-10-02 21:41:22

0

我會說你的解釋是正確的。當您取消註釋struct B{};時,struct B* p;行將簡單地引用該結構A::B

要回答你的問題,爲什麼當你離開struct B {};註釋掉時,名字struct B被插入全局範圍。我想這是因爲作者不希望你(有點)默默地聲明B作爲A的成員,而不使用成員規範作爲名稱B