在學習stl的過程當中,經常會遇到一些讓人難以理解的c++**,比如:
typedef
typename std::vector
::size_type size_type;
看起來它應該是定義乙個型別別名,但是typedef使用方式應該是typedef + 原型別名 + 新型別名(typedef具體使用方法可移步 typedef和#define的用法與區別 ),為何此處多了個typename?typename又是什麼東西?
typedef
char
* pchar;
只記得泛型程式設計(gp)當中,若是對模板類/函式進行定義時,可以使用template或者template,且這兩者是等價的。
那麼如上語句中的typename關鍵字是起了什麼作用呢?
檢視侯捷的《stl原始碼剖析》一書,其為:
template
<
classt,
class
alloc
=alloc>
class
vector
;
原來vector::size_type是vector中的巢狀型別,其實際等價於stl中大面積使用的可跨平台的size_t型別。
使用 typename 關鍵字的意義
將語句中的typename關鍵字拋開不看,則語句為:
typedef std::vector::size_type size_type;
1可以感覺到是對std::vector::size_type這個型別進行重新命名。那麼為什麼要加上typename這個關鍵字呢?
原來,其中t是模板中的型別引數,它只有等到模板例項化時才會知道是哪種型別,更不用說t內部的size_type。所以對於限定依賴名(解釋見補充)std::vector::size_type而言,無法判斷其是靜態成員變數/函式還是巢狀型別,這樣會造成語句的二義性,這是不能夠容忍的。
若是在std::vector::size_type這個型別前加上typename這一關鍵字,指明這是乙個巢狀型別,而不是t的靜態成員或靜態成員函式,消除了二義性。
總結根據以上的分析,可以知道語句的含義和作用是:
typedef建立了存在型別的別名,而typename告訴編譯器std::vector::size_type是乙個型別而不是乙個成員。
拓展:為何會有typename關鍵字
若是不加 typename 時,在如下模板定義會造成語句的二義性:
template
<
class
t>
void
foo(
)struct containsanothertype
;
然後如此例項化foo的型別引數:
foo()
;
那麼,t::iterator * iter;被編譯器例項化為containsanothertype::iterator * iter;。在這裡,前面是一靜態成員變數而不是型別,那麼這便成了乙個乘法表示式,不過iter在這裡沒有定義,編譯器會報錯:
error c2065: 『iter』 : undeclared identifier
但如果iter是乙個全域性變數,那麼這行**將完全正確,它是表示計算兩數相乘的表示式,返回值被拋棄。
如上造成了同一行**能以兩種完全不同的方式解釋,而且在模板例項化之前,完全沒有辦法來區分它們。
為解決該問題,c++標準委員會引入了typename關鍵字,使得模板類/函式在例項化前就區分其內部的依賴名(例如:vector::iterator viter;, 也稱dependent names)為靜態成員變數/函式還是巢狀型別。
補充:類外部訪問類內成員或名稱、(非)限定名、(非)依賴名
一、 類外部訪問類內成員或名稱
在類作用域概念中,在類外部訪問類中的名稱時,可以使用類作用域操作符::,形如myclass::name的呼叫通常存在三種:①靜態資料成員、②靜態成員函式和③巢狀型別:
struct myclass
myclass::a, myclass::b, myclass::c分別對應著上面三種。
二、限定名和非限定名
限定名(qualified name),就是限定了命名空間的名稱。看下面這段**,cout和endl就是限定名:
#include
intmain()
cout和endl前面都有std::,它限定了std這個命名空間,因此稱其為限定名。
如果在上面這段**中,前面用using std::cout;或者using namespace std;,然後使用時只用cout和endl,它們的前面不再有空間限定std::,所以此時的cout和endl就叫做非限定名(unqualified name)。
三、依賴名和非依賴名
依賴名(dependent name) 是指依賴於模板引數的名稱,而 非依賴名(non-dependent name) 則相反,指不依賴於模板引數的名稱。看下面這段**:
template
<
class
t>
class
myclass
;
因為是內建型別,所以類中前三個定義的型別在宣告這個模板類時就已知。然而對於接下來的三行定義,只有在模板例項化時才能知道它們的型別,因為它們都依賴於模板引數t。因此,t, vector和vector::iterator稱為依賴名。前三個定義叫做非依賴名。
更為複雜一點,如果用了typedef t u; u u;,雖然t沒再出現,但是u仍然是依賴名。由此可見,不管是直接還是間接,只要依賴於模板引數,該名稱就是依賴名。
參考部落格:
typedef typename 的作用
typedef的用法以及與define 的區別
typedef為c語言的關鍵字,作用是為一種資料型別定義乙個新名字。這裡的資料型別包括內部資料型別 int,char等 和自定義的資料型別 struct等 在程式設計中使用typedef目的一般有兩個,乙個是給變數乙個易記且意義明確的新名字,另乙個是簡化一些比較複雜的型別宣告。至於typedef有什...
typedef和 define的用法以及區別
一 typedef的用法 在c c 語言中,typedef常用來定義乙個識別符號及關鍵字的別名,它是語言編譯過程的一部分,但它並不實際分配記憶體空間,例項像 typedef int int typedef int array 10 typedef int pint typedef可以增強程式的可讀性...
typedef以及複雜資料型別解析
不管實在c還是c 中,typedef這個詞都不少見,當然出現頻率較高的還是在c 中。typedef與 define有些相似,但更多的是不同,特別是在一些複雜的用法上,就完全不同了,看了網上一些c c 的學習者的部落格,其中有一篇關於typedef的總結還是很不錯,由於總結的很好,我就不加修改的引用過...