C++模板(template)中typename

一、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; }
相關文章
相關標籤/搜索