C++泛型編程之函數模板
泛型語義
泛型(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++泛型編程之函數模板