在泛型程式設計的形參表中,關鍵字typename和class具有相同的含義,可以相互使用,兩個關鍵字都可以在同一模板形參表中使用:
1. typename用在模板定義裡,標明其後的模板參數是型別參數。
template<typename T,class U> calc (const T&, const U& ); // 定義一個返回參數中較大者的通用函數template <typename T>const T& max(const T& x, const T& y){ if (y < x) { return x; } return y;}
這種情況下,typename可用另一個的等效關鍵字class代替,如下片段所示:
// 定義一個返回參數中較大者的通用函數template <class T>const T& max(const T& x, const T& y){ if (y < x) { return x; } return y;} 引入這個關鍵字主要是為了避免class可能給人帶來的混淆:
使用關鍵字typdef 代替關鍵字class制定模板類型形參也許更為直觀,畢竟,可以使用內建類型(而不僅僅只是類類型)作為實際的類型形參,而且,更清楚地聲明後面的名字是一個類型名。關鍵字typedef作為標準c++的組成部分假如到c++中的,因此舊的程式可能只是用class用來修飾泛型程式設計的形參類型。
2, 模板中標明“內嵌依賴類型名”:內嵌依賴類型名(nested dependent type name)
.本來typename的用法就是這麼簡單, 但是STL原始碼中還有typename的一種不常見的用法:
例1:
請看SGI STL裡的一個例子, 只是STL中count範型演算法的實現:
template <class _InputIter, class _Tp>typename iterator_traits<_InputIter>::difference_typecount(_InputIter __first, _InputIter __last, const _Tp& __value) { __STL_REQUIRES(_InputIter, _InputIterator); __STL_REQUIRES(typename iterator_traits<_InputIter>::value_type, _EqualityComparable); __STL_REQUIRES(_Tp, _EqualityComparable); typename iterator_traits<_InputIter>::difference_type __n = 0; for ( ; __first != __last; ++__first) if (*__first == __value) ++__n; return __n;}這裡有三個地方用到了typename:傳回值、參數、變數定義。分別是:
typename iterator_traits<_InputIter>::difference_type
typename iterator_traits<_InputIter>::value_type
typename iterator_traits<_InputIter>::difference_type __n = 0; difference_type, value_type就是依賴於_InputIter(模板型別參數)的類型名。源碼如下:
template <class _Iterator>struct iterator_traits { typedef typename _Iterator::iterator_category iterator_category; typedef typename _Iterator::value_type value_type; typedef typename _Iterator::difference_type difference_type; typedef typename _Iterator::pointer pointer; typedef typename _Iterator::reference reference;}; 內嵌是指定義在類名的定義中的。以上difference_type和value_type都是定義在iterator_traits中的。
依賴是指依賴於一個模板參數。typename iterator_traits<_InputIter>::difference_type中difference_type依賴於模板參數_InputIter.
類型名是指這裡最終要指出的是個類型名,而不是變數。例如iterator_traits<_InputIter>::difference_type完全有可能是類iterator_traits<_InputIter>類裡的一個static對
象。而且當我們這樣寫的時候,C++預設就是解釋為一個變數的。所以,為了和變數區分,必須使用typename告訴編譯器。
那麼是不是所有的T::type_or_variable, 或者tmpl<T>:type_or_variable都需要使用typename呢。不是,有以下兩個例外。 3 例外
(1)類模板定義中的基類列表。 例如
template<class T>class Derived: public Base<T>::XXX{...}(2)類模板定義中的初始化列表。
Derived(int x) : Base<T>::xxx(x){...} 為什麼這裡不需要呢。因為編譯器知道這裡需要的是類型還是變數,
(1)基類列表裡肯定是類型名,(2)初始化列表裡肯定是成員變數名。 例2:
在模板定義內部指定類型。如下面代碼:
typename<class Parm,class U>Parm fcn(Parm* array,U value){ Parm::size_type *p; //如果Parm::size_type是一個類型,這句話的意思就是聲明一個變數 //如果如果Parm::size_type是一個變數(對象),這句話的意思就是乘法運算}
假如像上面的代碼一樣在模板中使用這種語句,則編譯器將無法辨別Parm::size_type是一個變數還是一個類型。所以必須顯式的告訴編譯器:
Parm::size_type是一個類型:
則函數模板變為如下所示:
typename<class Parm,class U>Parm fcn(Parm* array,U value){ typename Parm::size_type *p;}
部分內容來自http://c.chinaitlab.com/cc/basic/200907/788872.html