1. 程式人生 > >C++泛型編程之函數模板

C++泛型編程之函數模板

默認參數 soft 需要 mys 信息 ... 數據類型 交互 實現

泛型語義

  泛型(Generic Programming),即是指具有在多種數據類型上皆可操作的含意。泛型編
程的代表作品 STL 是一種高效、泛型、可交互操作的軟件組件。
  泛型編程最初誕生於 C++中,目的是為了實現 C++的 STL(標準模板庫)。其語言支
持機制就是模板(Templates)。
  模板的精神其實很簡單:類型參數化(type parameterized),即,類型也是一種參數,
也是一種靜多態。 換句話說, 把一個原本特定於某個類型的算法或類當中的類型信息抽掉,
抽出來做成模板參數。

函數模板

引子:重載函數,雖然在一定程度上達到了多類型適應的目的,但是不徹底,且有二義性存在。

#include <iostream>
using namespace std;
void myswap(int & a, int &b)
{   
int t = a;   a = b;   b = t; }
void myswap(
double & a, double &b)
{   
double t = a;   a = b;   b = t; }

int main()
{   
long a = 2; long b = 3;   myswap(a,b); //ambiguous   cout<<a<<b<<endl;   
return 0; }

函數模板

語法:在一個函數的參數表, 返回類型和函數體中使用參數化的類型。

template<typename/class 類型參數 T1, typename/class 類型參數 T2,...>

特點:結構上與普通函數無異,但是在傳入參數和返回值上做了泛化

返回類型 函數模板名(函數參數列表)
{
函數模板定義體
}

案例:(概念比較抽象,請通過案例來觀察其特點)

技術分享圖片

關於類型,今後我們會在博客的叠代中說明,多個不同類型參數的情況如何處理。

函數模板與普通函數的區別無非就是將函數參數高度抽象化,使其具備處理更多數據類型的能力。

特性小結

1)嚴格匹配,不存在隱式轉化。

2)先實例化,再調用。

3)類型參數可以省略。

4)尺有所長,寸有所短。

原理:

  編譯器並不是把函數模板處理成能夠處理任意類的函數; 編譯器從函數模板通過
具體類型產生不同的函數; 編譯器會對函數模板進行兩次編譯: 在聲明的地方對模板
代碼本身進行編譯, 在調用的地方對參數替換後的代碼進行編譯。

函數模板的應用——將快速排序算法實現模板化

#include <iostream>
#include <typeinfo>
using namespace std;

template
<typename T> void quickSort(T * array,int left, int right) {   if(left<right)   {     int low = left; int high = right;     T pivot = array[low];     while(low<high)     {       while(array[high] >= pivot && high>low )         high--;       array[low] = array[high];       while(array[low] <= pivot&& high>low)         low++;       array[high] = array[low];
    }
  array[low]
= pivot;   quickSort(array,left,low-1);   quickSort(array,low+1,right);   } }

int main() {   
int array[10] = {1,3,5,7,2,4,6,8,0,9};   quickSort<int>(array,0,9);   for(auto i:array)   {     cout<<i<<endl;   } }

函數模板的默認參數

  函數模板,在調用時,先實例化為模板函數,然後再調用。當然也可以設置默認類
型的默認值。由於系統強大的自動推導能力,有時默認也沒有太大的意義。

template<typename T = int>
void quickSort(T * array,int left, int right)

模板特化

  就是在實例化模板時,對特定類型的實參進行特殊處理,即實例化一個特殊的實例版本。

template<typename T> int compare( T &a, T &b)
template<> int compare < const char * >( const char* &a, const char* &b)

  當以特化定義時的形參使用模板時,將調用特化版本,模板特化分為全特化和偏特
化,函數模板的特化,只能全特化;

  比如我們在比較兩個數的大小時:

#include <iostream>
#include <string.h>
using namespace std;
template
<typename T> int compare( T &a, T &b) {   if(a > b) return 1;   else if(a < b)return -1;   else return 0; }


//實參為兩個 char 指針時, 比較的是指針的大小, //而不是指針指向內容的大小, 此時就需要為該函數模板定義一個特化版本, 即特殊處理的版本: template<> int compare < const char * >( const char* &a, const char* &b) {   return strcmp(a,b); }
int main() {   
int a = 3; int b = 5;   cout<<compare(a,b)<<endl;   string str1 = "abc",str2 ="abc";   cout<<compare(str1,str2)<<endl;   char * p1 = "abc",*p2= "def";   cout<<compare(p1,p2)<<endl;   cout<<compare(p2,p1)<<endl;   return 0; }

關於模板特化的認識

模板特化的原因:當前函數模板的邏輯或者功能,不能滿足特定參數的需求。

模板特化的方式:將需要特化的參數提前”布置“到模板中去,提前預定模板,之後傳入需要特化的參數時便可以

優先調用經過該參數特化的模板。

適用場景

  函數模板,只適用於函數的參數個數相同而類型不同,且函數體相同的情況。如果
個數不同,則不能用函數模板。

C++泛型編程之函數模板