1. 程式人生 > >template之模板中class與typename區別

template之模板中class與typename區別

前言

在分析traits程式設計之前, 我們需要對模板引數型別tempnameclass有一定的瞭解, 要明白他們在哪些方面不同, 哪些方面相同, 這樣才能對體會到traits程式設計的核心. 如果你已經明白了兩者, 那麼你可以直接看下一篇了.

相同之處

一般對模板引數型別typenameclass認為是一樣的. 這兩者在引數型別中確實是一樣的. 你可以寫成

template<class T> 
class point {};

也可以寫成

template<typename T>
class point {};

這兩者都是一樣的, 沒有區別. 兩者typename

class引數型別中沒有不同

既然相同又為什麼定義這兩個符號呢?

  1. 最開始定義定義模板的方法就是template<class T> , 但是class畢竟都認為是一個類, 在使用時難免會有些點混淆, 也就定義了typename來標誌引數型別
  2. 最重要關於 typename可以使用巢狀依賴型別, 也就是型別可以巢狀使用. 這也是兩個的不同之處.

不同之處

typename可以用在巢狀依賴中, 並且表示其型別, 而class並沒有這樣的功能.

什麼是巢狀依賴? 我們以一個簡單的例項來看

template<class T>
class people
{
public: typedef T value_type; typedef T* pointer; typedef T& reference; }; template<class T> struct man { public: typedef typename T::value_type value_type; typedef typename T::pointer pointer; typedef typename T::reference reference; void print() { cout << "man"
<< endl; } }; int main() { man<people<int>> Man; Man.print(); exit(0); }

以上就是typename的巢狀使用. typename告訴編譯器這不是一個函式, 也不是一個變數而是一個型別. 這裡使用typedef又將引數型別重新定義一次, 1. 增加了一層間接性, 2. 使用的時候也不需要在寫很長的程式碼.

這裡typename是對people類中定義的型別進行了一次提取, 這裡將typename改為class就會出錯.

typename主要的作用:

  • 對於模板引數是類的時候, typename能夠提取出該類所定義的引數型別.

並不是所有的巢狀依賴型別都要加上typename, 有一個例外 : 當繼承列表或成員初始化列表中對基類進行初始化的時候, 可以去掉typename關鍵字

man(int x) : T::value_type(x) {}

總結

這裡對typename做了一個淺顯的分析, 這也足夠我們可以分析traits程式設計的基礎了. 我再將以上的分析做一個歸納.

  1. typenameclass在作為引數型別時用法一樣, 沒有區別
  2. typename主要用於對巢狀依賴型別進行提取(萃取). 而class沒有這樣的功能.
  3. typename提取的一個例外是在繼承或成員初始化列表中對基類進行初始化時不用加typename關鍵字