程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++ 中 typename,typename

C++ 中 typename,typename

編輯:C++入門知識

C++ 中 typename,typename


聲明template參數時, 前綴關鍵字class和typename可以互換;

使用關鍵字typename標識嵌套從屬類型名稱, 但不需在基類列表和成員初始化列表內使用.


從屬名稱(dependent names): 模板(template)內出現的名稱, 相依於某個模板(template)參數, 如T t;

嵌套從屬名稱(nested dependent names):從屬名稱在class內呈嵌套裝, 如T::const_iterator ci;

非從屬名稱(non-dependent names): 不依賴任何template參數的名稱, 如int value;


如果不特定指出typename, 嵌套從屬名稱, 有可能產生解析(parse)歧義.

任何時候在模板(template)中指涉一個嵌套從屬類型名稱, 需要在前一個位置, 添加關鍵字typename;

否則報錯(GCC): error: need 'typename' before 'T::xxx' because 'T' is a dependent scope

#include <iostream>  
#include <string>  
#include <vector>  
      
using namespace std;  
      
template<typename T>  
void print2nd(const T& container) {  
    typename T::const_iterator iter(container.begin()); //未加typename, 報錯  
    ++iter;  
    int value = *iter;  
    std::cout << value;  
}  
      
int main () {  
    vector<int> vi = {1,2,3,4,5};  
    print2nd(vi);  
      
    return 0;  
}

例外:嵌套從屬類型名稱, 如果是基類列表(base class list)和成員初值列(member initialization list)中,不使用typename;為什麼這裡不需要呢?因為編譯器知道這裡需要的是類型還是變量,(1)基類列表裡肯定是類型名,(2)初始化列表裡肯定是成員變量名。

#include <iostream>  
#include <vector>       
using namespace std;  
      
struct Number {  
    Number(int x) {  
        std::cout << "Number = " << x << std::endl;  
    }  
};  
      
template<typename T>  
struct Base{  
    typedef Number Nested;  
};  
      
template<typename T>  
class Derived: public Base<T>::Nested { //不用typename  
public:  
    explicit Derived(int x) : Base<T>::Nested(x) { //不用typename  
        typename Base<T>::Nested temp(7); //必須使用  
    }  
};  
      
int main () {  
    Derived<int> d(5);  
      
    return 0;  
}

當使用特性類(traits class)時, 必須使用typename, 如

#include <array>  
#include <iostream>  
using namespace std;  
      
template<typename T>  
void workWithIter(T iter) {  
    typedef typename std::iterator_traits<T>::value_type value_type; //使用typename  
    value_type temp(*iter);  
    std::cout << "temp = " << temp << std::endl;  
      
}  
      
int main () {  
    std::array<int, 5> ai = {1,2,3,4,5};  
    std::array<int, 5>::iterator aiIter = ai.begin();  
    workWithIter(aiIter);  
    return 0;  
}

另附:

//下面來討論typename的第二種用法。現在假設我們有一個類如下:
   template <typename T> class Y
   {
       T::iterator *iter;
       ...
   };
   /* 我們可能本意是想定義一個迭代器對象,例如我們如果用vector<int>來實例化這個模板,那麼iter
   則應該是一個迭代器指針,但是,如果我們用下面這個類來實例化這個模板:*/
   class cType
   {
       static int iterator;
       ...
   };
   /* 那麼T::iterator *iter會被編譯器解釋為兩個數相乘。事實上,C++編譯器會采用第二種解釋方法
   ,即使iterator的確是一個類型名。
   為了避免這種矛盾,當我們適用qualified dependent name的時候,需要用typename來指出這是一個
   類型名.即: */
   template <typename T> class Y
   {
       typename T::iterator *iter;
       typedef typename T::iterator iterator; //定義了Y::iterator類型名稱
       ...
   };
   //typename 指出下面緊跟著的名稱是一個類型

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved