簡體   English   中英

同樣關於typename和template關鍵字

[英]Again on typename and template keywords

我已經仔細閱讀了很多關於這個主題的答案,但是在非模板函數(嵌套模板類的成員)的范圍內,當這兩個關鍵字不需要這些關鍵字時,我無法弄清楚。

我的參考編譯器是GNU g ++ 4.9.2和clang 3.5.0。

它們在下面的代碼中幾乎沒有什么不同,我把嵌入的注釋試圖解釋會發生什么。

#include <iostream>

// a simple template class with a public member template struct
template <class Z>
class Pa
{
// anything
public:
    template <class U>
    struct Pe  // a nested template
    {
        // anything
        void f(const char *); // a non-template member function
    };

    template <class U> friend struct Pe;
};

// definition of the function f
template <class AAA>
template <class BBB>
void Pa<AAA> :: Pe<BBB> :: f(const char* c)
{
    Pa<AAA> p; // NO typename for both clang and GNU...

    // the following line is ACCEPTED by both clang and GNU
    // without both template and typename keywords
    // However removing comments from typename only
    // makes clang still accepting the code while GNU doesn't
    // accept it anymore. The same happens if the comments   of template
    // ONLY are removed.
    //  
    // Finally both compilers accept the line when both typename AND
    // template are present...
    /*typename*/ Pa<AAA>::/*template*/ Pe<BBB> q;

    // in the following clang ACCEPTS typename, GNU doesn't:
    /*typename*/ Pa<AAA>::Pe<int> qq;

    // the following are accepted by both compilers
    // no matter whether both typename AND template
    // keywords are present OR commented out:
    typename Pa<int>::template Pe<double> qqq;
    typename Pa<double>::template Pe<BBB>  qqqq;
    std::cout << c << std::endl; // just to do something...
}

int main()
{
    Pa<char>::Pe<int> pp;
    pp.f("bye");
}

那么,在f的范圍內是否是Pa<double>::Pe<BBB>一個從屬名稱?

那么Pa<AAA>::Pe<int>怎么樣?

畢竟,為什么兩個引用編譯器的這種不同行為?

任何人都可以澄清解決難題嗎?

[temp.res]中的重要規則是:

qualified-id旨在引用不是當前實例化成員的類型(14.6.2.1)並且其嵌套名稱說明符引用依賴類型時,它應以關鍵字typename作為前綴,形成typename-specifier 如果typename-specifier中的qualified-id不表示類型,則程序格式錯誤。

這個問題圍繞着兩個合格身份

Pa<double>::Pe<BBB>
Pa<AAA>::Pe<int>

首先,什么是依賴類型? 根據[temp.dep.type]:

如果是,則類型依賴於
- 模板參數,
- 未知專業的成員,
- 作為當前實例化的從屬成員的嵌套類或枚舉,
- cv-qualified類型所依賴的cv限定類型,
- 由任何依賴類型構成的復合類型,
- 一個數組類型,其元素類型是依賴的或其邊界(如果有)是依賴於值的,
- 一個simple-template-id ,其中模板名稱是模板參數,或者任何模板參數是依賴類型或依賴於類型或依賴於值的表達式,或者
- 由decltype表達式 )表示,其中表達式依賴於類型(14.6.2.2)。

Pa<double> (第一個示例的嵌套名稱說明符 )不是依賴類型,因為它不適合任何項目符號。 由於我們不符合該標准,因此我們不需要為typename關鍵字添加前綴。

但是, Pa<AAA> 一個依賴類型,因為它是一個simple-template-id ,其中一個模板參數是一個依賴類型( AAA通常是一個依賴類型,因為它是一個模板參數)。

那么,什么是“當前實例化的成員”?

名稱是指當前實例化(如果是)
- [...]
- 在主類模板的定義或主類模板的成員中,類模板的名稱后跟<>中包含的主模板的模板參數列表(如下所述)(或等效的模板別名專用) )“ - 在類模板的嵌套類的定義中,作為當前實例化的成員引用的嵌套類的名稱,或者

在這種情況下,當前實例化是Pa<AAA> (或者也是Pa )。 和:

名稱是當前實例化的成員,如果它是[...] qualified-id ,其中嵌套名稱說明符引用當前實例化,並且當查找時,引用類的至少一個成員這是當前實例化或其非依賴基類。

所以Pe是當前實例化的成員。 因此,雖然Pa<AAA>::Pe<int>嵌套名稱說明符是依賴類型,但它是一個類型,它是當前實例化的成員,因此您不需要關鍵字typename 請注意, Pa<AAA>::Pe<int>本身一個依賴類型(它是一個嵌套類,它是當前實例化的依賴成員),但這本身就意味着需要typename關鍵字。

gcc在這里不接受typename這一事實:

/*typename*/ Pa<AAA>::Pe<int> qq;

因為它想要

typename Pa<AAA>::template Pe<int> qq;

是個bug。

暫無
暫無

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

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