條款 42:了解 typename 的雙重意義

Effective C++ 中文版 第三版》讀書筆記

條款 42:了解 typename 的雙重意義

template 聲明式中,class 和 typename 這兩個(gè)關(guān)鍵字意義完全相同

template<class T> class Widget;
template<typename T> class Widget;

有時(shí)候你一定要用 typename,

可以在 template 中指涉的兩種名稱:

template <typename C> 
void print2nd(const C& container) 
{ 
    if (container.size() >= 2) 
    { 
        C::const_iterator iter(container.begin()); 
        ++iter; 
        int value = *iter; 
        std::cout << value; 
    } 
}

iter 的類型是 C::const_iterator 實(shí)際上是什么必須取決于 template 參數(shù) C。template 內(nèi)出現(xiàn)的名稱如果相依于某個(gè) template 參數(shù),稱之為從屬名稱(dependent names)。如果從屬名稱在 class 內(nèi)呈嵌套狀,稱之為嵌套從屬名稱(nested dependent name)。C::const_iterator 就是這樣一個(gè)名稱嵌套從屬名稱。

value 類型 int。不依賴任何 template 參數(shù)的名稱。稱為非從屬名稱(non-dependent name)。

嵌套從屬名稱可能導(dǎo)致解析的困難:

template <typename C> 
void print2nd(const C& container) 
{ 
    C::const_iterator* x; 
}

看起來我們好像聲明一個(gè) local 變量,是個(gè)指針,指向一個(gè) C::const_iterator。 但它之所以被那么認(rèn)為,是因?yàn)槲覀?“已經(jīng)知道” C::const_iterator 是個(gè)類型。如果 C::const_iterator 不是個(gè)類型呢?如果 C 有個(gè) static 成員變量碰巧被命名為 const_iterator。過時(shí) x 碰巧是個(gè) global 變量名稱,那樣上述代碼就是一個(gè)相乘動(dòng)作,C::const_iterator 乘以 x。撰寫 C++ 解析器的人必須操心所有可能的輸入。

在我們知道 C 以前,沒有任何辦法可以知道 C::const_iterator 是否為一個(gè)類型。而當(dāng)編譯器開始解析 template print2nd 時(shí),尚未確定 C 是什么東西。

C++ 有個(gè)規(guī)則可以解析此一歧義狀態(tài):如果解析器在 template 中遭遇一個(gè)嵌套從屬名稱,它便假設(shè)這個(gè)名稱不是個(gè)類型,除非你告訴它是。缺省情況下從屬名稱不是類型。此外還有個(gè)例外。

所以上述代碼不是有效的 C++ 代碼。我們必須告訴 C++ 說 C::const_iterator 是個(gè)類型。只要緊鄰它之前放置關(guān)鍵字 typename 即可:

template <typename C> //這個(gè)合法的 C++ 代碼 
void print2nd(const C& container) 
{ 
    if (container.size() >= 2) 
    { 
        typename C::const_iterator iter(container.begin()); 
        ++iter; 
        int value = *iter; 
        std::cout << value; 
    } 
}

typename 只用來驗(yàn)明嵌套從屬類型名稱;其他名稱不該有它存在。

template <typename C> 
void f(const C& container, // 不允許使用 typename 
       typename C::iterator iter);// 一定要使用 typename

“typename 必須作為嵌套從屬類型名稱的前綴詞” 這一規(guī)則的例外是,typename 不可以出現(xiàn)在 base classes list 內(nèi)的嵌套從屬類型名稱之前,也不可在 member initialization list(成員初始化列表)中作為 base class 修飾符。例如:

template <typename T> 
class Derived: public Base<T>::Nested{ // base class list中不允許“typename” 
public: 
    explicit Derived(int x) 
        :Base<T>::Nested(x)//mem.init.list中不允許“typename” 
    { 
       typename Base<T>::Nested temp;//嵌套從屬類型既不在base class list中也不在mem.init.list中, 
    }  // 作為一個(gè)base class修飾符需加上typename 
};

讓我們看一個(gè) typename 例子:一個(gè) function template,他接受一個(gè)迭代器,而我們打算為該迭代器指涉的對(duì)象做一份復(fù)件 temp:

template <typename IterT> 
void workWithIterator(IterT) 
{ 
    typename std::iterator_traits<IterT>::value_type temp(*iter); 
}

這是個(gè)標(biāo)準(zhǔn) trait class 的一種運(yùn)用(條款 47),相當(dāng)于說 “類型 IterT 之對(duì)象所指之物的類型”。如果 IterT 是 vector<int>::iterator,temp 的類型就是 int,如果 IterT 是 list<string>::iterator,temp 的類型就是 string。由于 std::iterator_traits<IterT>::value_type 是個(gè)嵌套從屬類型名稱(value_type 被嵌套于 iterator_traits<IterT> 之內(nèi)而 IterT 是個(gè) template 參數(shù)),所以必須在它之前放置 typename。

這么長(zhǎng)你肯定會(huì)想建立一個(gè) typedef。對(duì)于 traits 成員名稱如 value_type,普遍習(xí)慣是設(shè)定 typedef 名稱用以代表某個(gè) traits 成員名稱:

template <typename IterT>
void workWithIterator(IterT)
{
typedef typename std::iterator_traits<IterT>::value_type value_type;
value_type temp(*iter);
}

請(qǐng)記住:

  1. 聲明 template 參數(shù)時(shí),前綴關(guān)鍵字 class 和 typename 可互換。

  2. 請(qǐng)使用關(guān)鍵字 typename 標(biāo)識(shí)嵌套從屬類型名稱;但不得在 base class list(基類列表)或 member initialization list(成員初值列表)內(nèi)以它作為 base class 修飾符。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評(píng)論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,559評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,442評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,581評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,922評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評(píng)論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,096評(píng)論 0 290
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,639評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,374評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,591評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,789評(píng)論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評(píng)論 1 295
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,322評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,554評(píng)論 2 379

推薦閱讀更多精彩內(nèi)容

  • 提一個(gè)問題:以下template聲明式中,class和typename有什么不同? 答案:沒有不同。當(dāng)我們聲明te...
    何幻閱讀 1,552評(píng)論 0 0
  • 再讀高效c++,頗有收獲,現(xiàn)將高效c++中的經(jīng)典分享如下,希望對(duì)你有所幫助。 1、盡量以const \enum\i...
    橙小汁閱讀 1,236評(píng)論 0 1
  • 本原則討論的是typename,這個(gè)typename是個(gè)啥玩意呢,你經(jīng)常會(huì)在泛型編程中見到如下代碼: 這倆是在一般...
    Stroman閱讀 604評(píng)論 0 0
  • 這里把STL里處理iterator的tag-dispatching + trait class機(jī)制提取一點(diǎn)出來并淺...
    Quasars閱讀 553評(píng)論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,826評(píng)論 18 139