C++中typename技術探索

C++中typename技術探索

【原創文章,轉載請保留或註明出處:http://blog.csdn.net/yinyhy/article/details/8672813

1.前言

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

       typename指示一個類型名,而非定義一個類型,以下聲明瞭一個Seq::iterator類型的變量itr,其中Seq是一個模板實例化時才知道的類:

typenameSeq::iterator itr;
如果沒有typename指示,Seq::iterator會被認爲是Seq的靜態變量,而不是類型名。typename關鍵字不會定義一個類型,如果你想定義一個新類型的話,你必須這樣:

typedef typenameSeq::iterator ITR;

2.typedef和typename

2.1typedef

類型說明的格式爲: 

typedef 類型 定義名; 

類型說明只定義了一個數據類型的新名字,而不是定義一種新的數據類型。定義名錶示這個類型的新名字。

例如: 用下面語句定義整型數的新名字: 

typedef int SIGNED_INT; 

使用說明後,SIGNED_INT就成爲int的同義詞了, 此時可以用SIGNED_INT定 義整型變量。例如: SIGNED_INT i, j;(與int i, j等效)。 

但longSIGNED_INT i, j; 是非法的。

typedef同樣可用來說明結構、聯合以及枚舉和類。

說明一個結構的格式爲: 

typedefstruct{ 
          數據類型 成員名; 
          數據類型 成員名; 
          ... 
        }結構名;

此時可直接用結構名定義結構變量了。

例如:

typedefstruct{ 
          char name[8]; 
          int class; 
          char subclass[6]; 
          float math, phys, chem,engl, biol; 
      }student; 
      student Liuqi;

則Liuqi被定義爲結構數組和結構指針。

2.2typename

       typename關鍵字告訴了編譯器把一個特殊的名字解釋成一個類型,在下列情況下必須對一個name使用typename關鍵字:

1)一個唯一的name(可以作爲類型理解),它嵌套在另一個類型中的。

2)依賴於一個模板參數,就是說:模板參數在某種程度上包含這個name。當模板參數使編譯器在指認一個類型時產生了誤解。

保險起見,你應該在所有編譯器可能錯把一個type當成一個變量的地方使用typename。就像上面那個例子中的T::id,因爲我們使用了typename,所以編譯器就知道了它是一個類型,可以用來聲明並創建實例。

3.typename示例

如果你的類型在模板參數中是有限制的,那你就必須使用typename

#include <iostream>
#include <typeinfo> // for typeid() operator

using namespace std;

template <typename TP>
struct COne {   // default member is public
    typedef TP one_value_type;
};

template <typename COne>  // 用一個模板類作爲模板參數, 這是很常見的
struct CTwo {
    // 請注意以下兩行
    // typedef COne:one_value_type two_value_type;  // *1
    typedef typename COne:one_value_type two_value_type; //*2 
};

// 以上兩個模板類只是定義了兩個內部的public類型, 但請注意第二個類CTwo的two_value_type類型
// 依賴COne的one_value_type, 而後者又取決於COne模板類實例化時傳入的參數類型.

int main()
{
    typedef COne<int> OneInt_type;
    typedef CTwo< OneInt_type > TwoInt_type;
    TwoInt_type::two_value_type i;
    int j;
    if ( typeid(i) == typeid(j) )   // 如果i是int型變量
        cout << "Right!"<< endl;   // 打印Right
    return;
}

       以上例子在Linux下用G++ 2.93編譯通過, 結果打印"Right". 但是如果把*1行的註釋號去掉, 註釋,*2行, 則編譯時報錯, 編譯器不知道COne:one_value_type爲何物。通常在模板類參數中的類型到實例化之後纔會顯露真身, 但這個CTwo類偏偏又要依賴一個已經存在的COne模板類, 希望能夠預先保證CTwo::two_value_type與COne:one_value屬於同一類型, 這是就只好請typename出山, 告訴編譯器, 後面的COne:one_value_type是一個已經存在於某處的類型的名字(type name), 這樣編譯器就可以順利的工作了。

4.typename含義

typename:的含義有兩個:
1)typenamevar_name,表示var_name的定義還沒有給出,這個語句通常出現在模版的定義內。例如:
template
void f()
{
  typedef typename T::A TA;    // 聲明 TA 的類型爲 T::A
  TAa5;                                  // 聲明 a5 的類型爲 TA
  typename T::Aa6;                 // 聲明 a6 的類型爲 T::A
  TA *pta6;                            //聲明 pta6 的類型爲 TA 的指針
}

因爲T是一個模版實例化時才知道的類型,所以編譯器更對T::A不知所云,爲了通知編譯器T::A是一個合法的類型,使用typename語句可以避免編譯器報錯。
2)template <typename var_name > class class_name,表示var_name是一個類型,在模版實例化時可以替換任意類型,不僅包括內置類型(int等),也包括自定義類型class。這就是問題中的形式。換句話說,在template中,typename和class的意義完全一樣。

5.內嵌依賴類型名

       這裏有三個詞,內嵌、依賴、類型名。那麼什麼是“內嵌依賴類型名(nesteddependent type name)”

請看SGI STL裏的一個例子,只是STL中count範型算法的實現:

template <class _InputIter, class_Tp>
typename iterator_traits<_InputIter>::difference_type
count(_InputIter __first, _InputIter __last, const _Tp& __value) {
  __STL_REQUIRES(_InputIter, _InputIterator);
  __STL_REQUIRES(typename iterator_traits<_InputIter>::value_type,
        _EqualityComparable);
  __STL_REQUIRES(_Tp, _EqualityComparable);
  typename iterator_traits<_InputIter>::difference_type __n = 0;
  for ( ; __first != __last; ++__first)
   if (*__first == __value)
   ++__n;
  return __n;
}

這裏有三個地方用到了typename:返回值、參數、變量定義。分別是

typename iterator_traits<_InputIter>::difference_type

typename iterator_traits<_InputIter>::value_type

typename iterator_traits<_InputIter>::difference_type __n = 0;

difference_type, value_type就是依賴於_InputIter(模板類型參數)的類型名。源碼如下:template <class_Iterator>

struct iterator_traits {
  typedef typename _Iterator::iterator_category iterator_category;
  typedef typename _Iterator::value_type    value_type;
  typedef typename _Iterator::difference_type   difference_type;
  typedef typename _Iterator::pointer     pointer;
  typedef typename _Iterator::reference    reference;
};

       內嵌是指定義在類名的定義中的。以上difference_type和value_type都是定義在iterator_traits中的。

       依賴是指依賴於一個模板參數。typename iterator_traits<_InputIter>::difference_type中difference_type依賴於模板參數_InputIter。

       類型名是指這裏最終要指出的是個類型名,而不是變量。例如iterator_traits<_InputIter>::difference_type完全有可能是類iterator_traits<_InputIter>類裏的一個static對象。而且當我們這樣寫的時候,C++默認就是解釋爲一個變量的。所以,爲了和變量區分,必須使用typename告訴編譯器。

6.參考文獻:

http://blog.csdn.net/wang37921/article/details/6014811

http://blog.sina.com.cn/s/blog_9151e7300100zzc5.html

http://3140618.blog.163.com/blog/static/74517972011222114728421/

發佈了20 篇原創文章 · 獲贊 13 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章