![](/img/trans.png)
[英]“typename” and “template” keywords: are they really necessary?
[英]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.