一、typename關鍵字
在聲明template參數時, 前綴關鍵字class和typename能夠互換,但在使用模板參數T的內部類型名稱即嵌套從屬名稱時只能用typename。ios
在C++標準化的過程當中,引入關鍵字typename
是爲了說明:模板類型參數內部的標識符(associated type,常見於STL中的各類容器)也能夠是一個類型:ui
好比:spa
template<typename T> class MyClass { typename T::SubType* ptr; }
這裏介紹模板內參數名稱的幾個概念;指針
從屬名稱(dependent names): 模板(template)內出現的名稱, 依賴於某個模板(template)參數, 如T t;
嵌套從屬名稱(nested dependent names):從屬名稱在class內呈嵌套裝, 如T::const_iterator ci;
非從屬名稱(non-dependent names): 不依賴任何template參數的名稱, 如int value;
任什麼時候候在模板(template)中指涉一個嵌套從屬類型名稱, 須要在前一個位置, 添加關鍵字typename;code
若是不特定指出typename, 嵌套從屬名稱, 有可能產生解析(parse)歧義,可能會報錯(GCC): error: need 'typename' before 'T::xxx' because 'T' is a dependent scope。對象
好比:blog
template<typename T> class MyClass { /*typename*/ T::SubType* ptr; }
上述程序中,第二個typename被用來講明,SubType是定義與類T內部的一種類型,也就是associated type,於是,ptr是一個指向T::SubType類型的指針。若是不使用typename,T::SubType會被優先看作T的一個靜態成員,也就是一個具體而變量或對象,因而,下面的表達式:ci
T::SubType* ptr;
編譯器此時就沒法辨別這SubType是什麼,由於SubType多是模板參數T內的一個static變量,ptr能夠當作一個全局變量,此時代碼會被看作類T的靜態成員SubType和ptr的乘積,或者SubType多是一個typedef好比編譯器
class Class_T{ typedef int SubType; ... };
那上面代碼轉化過來就是這樣:it
int *x;
二、嵌套從屬名稱使用typename的幾個場景
a、模板內出現的名稱若是依賴於某個模板參數,稱之爲從屬名稱(dependent name)。若是從屬名稱在class內呈嵌套狀,咱們稱爲嵌套從屬名稱(nested dependent name),舉例以下:
template<typename T> void print(const T & container) { T::const_iterator iter(container.begin()); cout << *iter << endl; int value = *iter; return; }
- 在上述代碼中,iter 的類型是依賴於模板參數T的,所以被稱爲 從屬名稱;
- 同理,value的類型是語言內置類型,不依賴於任何模板參數,所以被稱爲 非從屬名稱;
- C++編譯器在面對從屬名稱時,若是此時該從屬名稱又嵌套了其餘類型,如此處的 iter就是T::const_iterator類型,這裏的T::const_iterator 稱爲嵌套從屬類型名稱(嵌套於T類型,從屬於模板參數T)
或者
template<typename T> // typename allowed (as is "class") void f(const T& container, // typename not allowed typename T::iterator iter); // typename required
上述的T並非嵌套從屬類型名稱 (它並不是嵌套與任何「取決於模板參數」的東西內),因此聲明container時並不須要以typename爲前導。
但T::iterator是個嵌套從屬類型名稱,因此必須以typename爲前導。
b、某個模板類裏面typedef類型時,若是這個類型與模板參數T相關,就須要使用typename。即這樣的形式:
template <class T> class Test { public: typedef map<int, T> TEMPLATE_MAP; //TEMPLATE_MAP不須要typename,由於它不依賴其餘的名稱 typedef map<int, T>::iterator TEMPLATE_MAP_ITER; //error! 嵌套從屬名稱,依賴其餘類的iterator名稱 typedef typename map<int, T>::iterator TEMPLATE_MAP_ITER; //yes };
c、例外:嵌套從屬類型名稱, 若是是基類列表(base class list)和成員初值列(member initialization list)中,不使用typename;
/* * BInsertSort.cpp * * Created on: 2014.4.17 * Author: Spike */ #include <iostream> #include <vector> using namespace std; struct Number { Number(int x) { std::cout << "Number = " << x << std::endl; } }; template<typename T> struct Base{ typedef Number Nested; }; template<typename T> class Derived: public Base<T>::Nested { //不用typename public: explicit Derived(int x) : Base<T>::Nested(x) { //不用typename typename Base<T>::Nested temp(7); //必須使用 } }; int main () { Derived<int> d(5); return 0; }