C++ 模板格式

面向對象編程所依賴的多態性稱爲運行時多態性,泛型編程所依賴的多態性稱爲編譯時多態性或參數試多態性。
所以,要運用泛型編程,首先要了解模板的格式,本文分爲模板定義時與使用時格式詳解。

函數模板

定義

template<typename T> int compare(T&,T&){}
template<typename T> inline T min(const T&,const T&){}// inline說明符放在          形參表之後,返回類型之前。

使用
使用函數模板時,編譯器會推斷哪些模板實參綁定到模板形參,一旦確定了實際的模板實參,就稱它實例化了函數模板的一個實例

int main(){
cout<<compare(0,1)<<endl;//T is int,隱式調用
string s1 = "hi",s2 = "hello";
cout<<compare(s1,s2)<<endl;//T is string
}

當函數的返回類型必須與形參表中所用的所有類型都不相同時,推斷不了模板實參的類型。在這種情況下,有必要覆蓋模板實參推斷機制,並顯示指定爲模板實參所用的類型或值。
模板形參使用規則:

  • 可以給模板形參賦予的唯一含義是區別形參是類型形參還是非類模板
 template<class T,size_t N> void array_init(T(&parm)[N]){//size_t爲非類型形參
      for(size_t i = 0;i!=N;++i){ 
            parm[i] = 0;
    }    
  }//模板非類型形參是模板定義內部的常量值,在需要常量表達式的時候可使用非類型形參,例如指定數組的長度
  • 模板形參遵循常規名字屏蔽規則。在全局作用域中聲明的對象,函數或類型同名的模板形參會屏蔽全局名字
  • 用作模板形參的名字不能再模板內部重用,這還意味着模板形參的名字只能在同一模板形參表中使用一次:
template<class V,class V> V cale(const V&,const &V)//錯誤,形參表中兩個class V
  • 關鍵字typename和class具有相同的含義,可互換使用。但是關鍵字typename是作爲標準c++的組成部分計入到c++中的,因此舊的程序更有可能只用關鍵字class。
  • 如果要在函數模板內部使用類似size_type的類型,必須顯式地告訴編譯器我們正在使用的名字指的是一個類型。
template<class Parm,class U> Parm fcn(Parm *array,U value){
 typename Parm::size_type *p;//通過在成員名字前面加上關鍵字typename,可以告訴編譯器將成員當做類型。
}

如果拿不準是否需要以typename指明一個名字的類型,那麼指定它是個好主意,在類型前指定typename沒有害處,因此,即使typename是不必要的,也沒有關係。

類模板

接口定義

template<class Type> class Queue{
public:
   Queue();
   Type &front();
   const Type &front()const;
   void push(const Type&);
   void pop();
   bool empty() const;
private:
   //...
};    

使用
與調用函數模板形成對比,實用類模板時,必須爲模板形參顯示指定實參

Queue<int> qi;
Queue<vector<double>> qc;
Queue<string> qs;

類模板的每次實例化都會產生一個獨立的類類型。爲int類型實例化的Queue與任意其他Queue類型沒有關係,對其他Queue類型的成員也沒有特殊的訪問權。
用模板定義的類型總是包括模板實參,例如Queue不是類型,而Queue<int>Queue<string>是類型。

模板實參推斷

1.多個類型形參的實參必須完全匹配

template<typename T> int compare(T&,T&){}
int main(){
short si;
compare(si,1024);//錯誤,不能實例化爲compare(short,int)
return 0;
}

如果想允許實參的常規轉換,則函數必須用兩個類型形參來定義

2.類型形參的實參的受限轉換

一般而言不會轉換實參以匹配已有的實例化,相反,會產生新的實例。但以下兩種編譯器會執行轉換

  • const轉換:接收const引用或者const指針的函數可以分別用非const對象的引用或指針來調用,無需產生新的實例化。
  • 數組或者函數到指針的轉換:如果模板形參不是引用類型,則對數組或函數類型的實參應用常規指針轉換。
template<typename T> T fobj(T,T);
template<typename T> T fref(const &T,const&T);
string s1("a value");
const string s2("another value");
fobj(s1,s2);//正確,調用fobj(string,string),無視const
fref(s1,s2);//正確,非const對象s1轉換爲const引用。
int a[10],b[42];
fobj(a,b);//正確,調用fobj(int*,int*)
fref(a,b);//錯誤,當形參爲引用時,數組不能轉換爲指針

類型轉換的限制只適用於類型爲模板形參的那些實參。

3.模板實參推斷與函數指針

template<typename T> int compare(const T&,const T&);
int(*pf1)(const int&,const int&) = compare;//pf1的類型是一個指針,指向“接收兩個const int&類型形參並返回int值的函數”,指針pf1引用的是將T綁定到int的實例化。

如果不能從函數指針類型確定模板實參,就會出錯。

void func(int(*)(const string&,const string&));
void func(int(*)(const int&,const int&));
func(compare);//錯誤,通過查看func的形參類型不可能確定模板實參的唯一類型。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章