C++typename的由來和用法

2020-12-15 酷扯兒

本文轉載自【微信公眾號:羽林君,ID:Conscience_Remains】經微信公眾號授權轉載,如需轉載與原文作者聯繫

前言

在C++模板函數的使用過程中,我們經常可以看到一個typename的使用,例如這樣的操作

但是除此之外,我們也會經常看到這樣的用法

那麼這裡就要問大家,這C++類似的用法下有什麼區別呢,且聽我細細道來。

作者:良知猶存

轉載授權以及圍觀:歡迎添加微信公眾號:羽林君

由來分析

"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 的作用完全一樣

template<class T>

這裡

class

關鍵字表明T是一個類型,後來為了避免

在這兩個地方的使用可能給人帶來混淆,所以引入了

typename

這個關鍵字,它的作用同

一樣表明後面的符號為一個類型。

那class使用就夠了,為什麼又引入了新的關鍵詞 typename ,關於這個問題,Stan Lippman 曾在其博客中表示,最早 Stroustrup 使用

來聲明模板參數列表中的類型是為了避免增加不必要的關鍵字;後來委員會認為這樣混用可能造成概念上的混淆才加上了

關鍵字。

而使用

的作用就是告訴 c++ 編譯器,

後面的字符串為一個類型名稱,而不是成員函數或者成員變量,這個時候如果前面沒有

,編譯器沒有任何辦法知道 T::LengthType 是一個類型還是一個成員名稱(靜態數據成員或者靜態函數),所以編譯不能夠通過。

問題浮現

那麼問題來了,什麼情況下,class定義之後,編譯不能通過呢?

void fun(const T& proto){

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

發生編譯錯誤是因為編譯器不知道

T::const_iterator

是個類型。萬一它是個變量呢?

的解析有著邏輯上的矛盾: 直到確定了

T

是什麼東西,編譯器才會知道

是不是一個類型; 然而當模板被解析時,

還是不確定的。這時我們聲明它為一個類型才能通過編譯:

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

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

對於用於模板定義的依賴於模板參數的名稱,只有在實例化的參數中存在這個類型名,或者這個名稱前使用了

typename

關鍵字來修飾,編譯器才會將該名稱當成是類型。除了以上這兩種情況,絕不會被當成是類型。

因此,如果你想直接告訴編譯器

是類型而不是變量,只需用

修飾:

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

這樣編譯器就可以確定

是一個類型,而不再需要等到實例化時期才能確定,因此消除了前面提到的歧義。

嵌套從屬類型

事實上類型

依賴於模板參數

, 模板中依賴於模板參數的名稱稱為從屬名稱(dependent name), 當一個從屬名稱嵌套在一個類裡面時,稱為嵌套從屬名稱(nested dependent name)。 其實

還是一個嵌套從屬類型名稱(nested dependent type name)。

嵌套從屬名稱是需要用

聲明的,其他的名稱是不可以用

聲明的。比如下面是一個合法的聲明:

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

使用

在定義類模板或者函數模板時,

關鍵字都可以用於指定模板參數中的類型。也就是說,以下兩種用法是完全等價的。

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

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

既然

關鍵字已經存在,而且它也可以用於最常見的指定模板參數,那麼為什麼不廢除

這一用法呢?答案其實也很明顯,因為在最終的標準出來之前,所有已存在的書、文章、教學、代碼中都是使用的是

,可以想像,如果標準不再支持

,會出現什麼情況。

使用關鍵字

代替關鍵字

指定模板類型形參更為直觀,畢竟,可以使用內置類型(非類類型)作為實際的類型形參,而且,

更清楚地指明後面的名字是一個類型名。但是,關鍵字

是作為標準C++的組成部分加入到C++中的,因此舊的程序更有可能只用關鍵字

這就是我分享的c++的typename,此外如果大家有什麼更好的思路,也歡迎分享交流哈。

相關焦點

  • C++ typename的起源與用法
    偶然一個機遇,通過對typename關鍵字的梳理,我也終於對泛型編程的基本原理與應用場景有了進一步的理解。註:在C++模板庫以及遊戲引擎裡面,typename的身影隨處可見,模板編程裡面的泛型、完美轉發、類型萃取等重要功能都離不開typename。該文章由淺入深地講解了泛型中typename的原理和使用方法,一定會加深你對泛型編程的理解。
  • get_name(),get_full_name(),get_type_name()……傻傻分不清楚
    想弄清楚函數的功能,先清楚是誰的函數在UVM中,有幾個和「name」有關的「小」函數, 如get_name(), get_full_name(), get_type_name() ,set_name ()。
  • 英語make a name for 的用法
    在英語中,習語 make a name 就可以表達「成名」的意思,後面常跟介詞 for 來接為什麼人而成名。今天我們通過幾個例句來學習一下這個習語的用法。例句1:Tom has made a name for himself as a talented teacher.湯姆是出了名的有才華的教師。
  • C++整數常量的前綴和後綴
    C++整數常量的前綴和後綴 在C/C++中,整數常量可以加上不同的前綴,表示不同的進位:十進位:不帶前綴,默認表示為十進位;八進位:0 表示八進位;十六進位:0x 或 0X 表示十六進位。
  • 託福語法:介詞to和at的用法
    {"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","name":"name","type"
  • 雅思口語話題精講:Name
    {"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","name":"name","type"
  • 中考英語:形容詞和副詞的用法及練習
    {"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","name":"name","type"
  • 七年級英語「如果」和 「是否」用法訓練題
    {"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","name":"name","type"
  • 變量類型測試函數的使用:七、is_resource的用法
    講完PHP變量類型測試函數【is_object】的用法,今天來講講PHP變量類型測試函數【is_resource】的用法。is_resourceis_resource — 檢測變量是否為資源類型is_resource 描述is_resource ( mixed $var ) : bool「is_resource函數參數和前六個變量測試函數的用法是一模一樣的可以混合類型
  • 初一英語複習資料:My name’s Gina 單元測試題
    {"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","name":"name","type"
  • 七年級英語:also,too,either和as well用法區別
    {"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","name":"name","type"
  • 「big name」不是「大名字」,「pet name」也不是「寵物名」!
    大名一般都是指你的「名字」,也就是西方國家中的 "given name"或者「first name」。例句:He's a big-name performer.他是個大名鼎鼎的演員。What is your first name?(What is your given name?) 您的名字是什麼?。
  • 植樹節的由來(英文版)
    {"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","name":"name","type"
  • 美國感恩節的歷史由來
    {"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","name":"name","type"
  • 託福語法技巧:a/an的用法
    {"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","name":"name","type"
  • bring等帶來用法小結
    {"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","name":"name","type"
  • 「first name」 是名字,「given name」又是什麼意思呢?
    當你想要和老外交朋友時,該怎麼詢問對方的名字呢?大家可能脫口而出的是 "What's your name?"作為陌生人見面第一句,其實是略顯過時和粗魯的說法,我們該怎麼問才地道和顯得有禮貌呢?✨a.,名和姓之間的名字,是父母或親戚所取,一般取長者的名或姓3. last name / family name / surname 姓,last name 更常用,而 surname 更正式4. nickname / pet name
  • 國慶節的由來:國慶節英語簡介
    {"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","name":"name","type"
  • 聖誕故事集——聖誕節的由來
    {"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","name":"name","type"
  • Toefl聽力短語用法(2)
    {"name":{"label":"姓名","placeholder":"","required":1,"formType":"text","group":"basics","name":"name","type"