C++typename的由來和用法

前言html

   在C++模板函數的使用過程當中,咱們常常能夠看到一個typename的使用,例如這樣的操做linux

可是除此以外,咱們也會常常看到這樣的用法c++

那麼這裏就要問你們,這C++相似的用法下有什麼區別呢,且聽我細細道來。編程


做者:良知猶存微信

轉載受權以及圍觀:歡迎添加微信公衆號:羽林君app


由來分析框架

   "typename"是一個C++程序設計語言中的關鍵字。當用於泛型編程時是另外一術語"class"的同義詞。這個關鍵字用於指出模板聲明(或定義)中的非獨立名稱(dependent names)是類型名,而非變量名。編程語言

    

    咱們常常會這麼用 typename,這是一項C++編程語言的泛型編程(或曰「模板編程」)的功能,typename關鍵字用於引入一個模板參數。函數

template <typename T> const T& max(const T& x, const T& y) { if (y < x) { return x; } return y; } 

在模板定義語法中關鍵字 class 與 typename 的做用徹底同樣spa

template<class T> const T& max(const T& x, const T& y) { if (y < x) { return x; } return y; } 

    這裏 class 關鍵字代表T是一個類型,後來爲了不 class 在這兩個地方的使用可能給人帶來混淆,因此引入了 typename 這個關鍵字,它的做用同 class 同樣代表後面的符號爲一個類型。

    那class使用就夠了,爲何又引入了新的關鍵詞 typename ,關於這個問題,Stan Lippman 曾在其博客中表示,最先 Stroustrup 使用 class 來聲明模板參數列表中的類型是爲了不增長沒必要要的關鍵字;後來委員會認爲這樣混用可能形成概念上的混淆才加上了 typename 關鍵字。

        而使用 typename 的做用就是告訴 c++ 編譯器,typename 後面的字符串爲一個類型名稱,而不是成員函數或者成員變量,這個時候若是前面沒有 typename,編譯器沒有任何辦法知道 T::LengthType 是一個類型仍是一個成員名稱(靜態數據成員或者靜態函數),因此編譯不可以經過。

問題浮現

那麼問題來了,什麼狀況下,class定義以後,編譯不能經過呢?

template<typename T>
void fun(const T& proto){


        T::const_iterator it(proto.begin());
}

發生編譯錯誤是由於編譯器不知道T::const_iterator是個類型。萬一它是個變量呢? T::const_iterator的解析有着邏輯上的矛盾: 直到肯定了T是什麼東西,編譯器纔會知道T::const_iterator是否是一個類型; 然而當模板被解析時,T仍是不肯定的。這時咱們聲明它爲一個類型才能經過編譯:

    並且在模板實例化以前,徹底沒有辦法來區分它們,這絕對是滋生各類bug的溫牀。這時C++標準委員會再也忍不住了,與其到實例化時才能知道到底選擇哪一種方式來解釋以上代碼,委員會決定引入一個新的關鍵字,這就是typename

千呼萬喚始出來,咱們來看看C++標準:

對於用於模板定義的依賴於模板參數的名稱,只有在實例化的參數中存在這個類型名,或者這個名稱前使用了 typename 關鍵字來修飾,編譯器纔會將該名稱當成是類型。除了以上這兩種狀況,毫不會被當成是類型。

所以,若是你想直接告訴編譯器 T::const_iterator 是類型而不是變量,只需用 typename修飾:

typename    T::const_iterator it(proto.begin());

    這樣編譯器就能夠肯定T::const_iterator是一個類型,而再也不須要等到實例化時期才能肯定,所以消除了前面提到的歧義。

嵌套從屬類型

事實上類型T::const_iterator依賴於模板參數T, 模板中依賴於模板參數的名稱稱爲從屬名稱(dependent name), 當一個從屬名稱嵌套在一個類裏面時,稱爲嵌套從屬名稱(nested dependent name)。 其實T::const_iterator仍是一個嵌套從屬類型名稱(nested dependent type name)。

嵌套從屬名稱是須要用typename聲明的,其餘的名稱是不能夠用typename聲明的。好比下面是一個合法的聲明:

template<typename T> void fun(const T& proto ,typename  T::const_iterator it); 

使用

    在定義類模板或者函數模板時,typename 和 class 關鍵字均可以用於指定模板參數中的類型。也就是說,如下兩種用法是徹底等價的。

template<typename T> /* ... */; template<class T> /* ... */; 

既然typename關鍵字已經存在,並且它也能夠用於最多見的指定模板參數,那麼爲何不廢除class這一用法呢?答案其實也很明顯,由於在最終的標準出來以前,全部已存在的書、文章、教學、代碼中都是使用的是class,能夠想像,若是標準再也不支持class,會出現什麼狀況。

    使用關鍵字typename代替關鍵字class指定模板類型形參更爲直觀,畢竟,可使用內置類型(非類類型)做爲實際的類型形參,並且,typename更清楚地指明後面的名字是一個類型名。可是,關鍵字typename是做爲標準C++的組成部分加入到C++中的,所以舊的程序更有可能只用關鍵字class

這就是我分享的c++的typename,此外若是你們有什麼更好的思路,也歡迎分享交流哈。

END

推薦閱讀

【1】linux開發各類I/O操做簡析,以及select、poll、epoll機制的對比

【2】嵌入式底層開發的軟件框架簡述 

【3】CPU中的程序是怎麼運行起來的 必讀
【4】什麼?還不懂c++vector的用法,你憑什麼勇氣來的!
【5】階段性文章總結分析

本公衆號所有原創乾貨已整理成一個目錄,回覆[ 資源 ]便可得到。

參考連接:

https://liam.page/2018/03/16/keywords-typename-and-class-in-Cxx/

https://harttle.land/2015/09/09/effective-cpp-42.html

http://feihu.me/blog/2014/the-origin-and-usage-of-typename/

更多分享,掃碼關注我

相關文章
相關標籤/搜索