條款 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)記?。?/p>

  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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容