C++函數模闆 模闆執行個體化、具體化
函數模闆是C++新增的一種性質,它允許隻定義一次函數的實作,即可使用不同類型的參數來調用該函數。這樣做可以減小代碼的書寫的複雜度,同時也便于修改(注:使用模闆函數并不會減少最終可執行程式的大小,因為在調用模闆函數時,編譯器都根據調用時的參數類型進行了相應執行個體化)。下面來看看函數模闆的使用過程:
struct job
{
char name[20];
int salary;
};
template <class T> //函數模闆聲明,通用變量類型為T
void swap(T &a, T &b);
void showJob(const job &a);//列印job内容
using std::cin;
using std::cout;
using std::endl;
void main(void)
{
int a = 4;
int b = 5;
cout<<"Before swap a = "<<a<<" b="<<b<<endl;
swap(a, b);
cout<<"After swap a = "<<a<<" b="<<b<<endl;
job jobA = {"coder", 10000};
job jobB = {"manager", 1000};
cout<<"Before swap";
showJob(jobA);
showJob(jobB);
cout<<endl;
swap(jobA, jobB);
cout<<"After swap";
showJob(jobA);
showJob(jobB);
cout<<endl;
system("pause");
};
template<class T> //函數模闆實作
void swap(T &a, T &b)
{
T temp;
temp = a;
a = b;
b = temp;
}
void showJob(const job &a)
{
cout<<" "<<a.name<<" = "<<a.salary;
}
如果在上述job結構互換過程中隻想互換salary,而不換其他成員變量值那麼怎麼辦呢?C++中可以通過以下幾種方法來解決這一問題。
1>顯式具體化
顯式具體化也是基于函數模闆的,隻不過在函數模闆的基礎上,添加一個專門針對特定類型的、實作方式不同的具體化函數。
template<>void swap<job>(job &a, job &b)
{
int salary;
salary = a.salary;
a.salary = b.salary;
b.salary = salary;
}
如上所示,該具體化函數的實作與模闆并不一緻,編譯器解析函數調用時會選擇最比對的函數定義。
2>定義同名正常函數
void swap(job &a, job &b)
{
int salary;
salary = a.salary;
a.salary = b.salary;
b.salary = salary;
}
由于編譯器在重載解析時,會選擇最比對函數定義,是以在調用swap(jobA, jobB)時,編譯器會選擇void swap(job &a, job &b)函數定義,而屏蔽了模闆函數。
同時,模闆函數也可以重載,其操作與正常函數一緻。
template <class T> void swap(T &a, T &b);
template <class T> void swap(T &a, T &b, T &c);
template <typename T> void swap(T &a, T &b)
{
T temp;
temp = a;
a = b;
b = temp;
}
template <typename T> void swap(T &a, T &b, T &c)
{
T temp;
temp = a;
a = b;
b = c;
c = temp;
}
上面主要說的是函數模闆的具體化,下面說下模闆執行個體化。
函數模闆:
#define MAXNAME 128
struct job
{
char name[MAXNAME]:
int salary;
};
template<class T>
void swap(T &a, T &b )
{
T temp;
temp = a;
a = b;
b = temp;
};
template void swap<int>(int &a, int & b); //顯式執行個體化,隻需聲明
template<> void swap<job>(job &a, job &b) //顯式具體化(上面已經講過,注意與執行個體化區分開,必須有定義)
{
int salary:
salary = a.salary:
a.salary = b.salary;
b.salary = salary;
};//explicite specialization.
類模闆:
template <class T>
class Arrary
{
private:
T* ar;
int l;
...
};//template class declaration.
template class Array<int>; //explicit instantiation. 顯式執行個體化
template<> class Array<job>
{
private:
job* ar;
int l;
};//expicit specialization. 顯式具體化,類定義體可以不同于類模闆Array
相應的,隐式執行個體化指的是:在使用模闆之前,編譯器不生成模闆的聲明和定義執行個體。隻有當使用模闆時,編譯器才根據模闆定義生成相應類型的執行個體。如:
int i=0, j=1;
swap(i, j); //編譯器根據參數i,j的類型隐式地生成swap<int>(int &a, int &b)的函數定義。
Array<int> arVal;//編譯器根據類型參數隐式地生成Array<int>類聲明和類函數定義。
顯式執行個體化:
當顯式執行個體化模闆時,在使用模闆之前,編譯器根據顯式執行個體化指定的類型生成模闆執行個體。如前面顯示執行個體化(explicit instantiation)模闆函數和模闆類。其格式為:
template typename function<typename>(argulist);
template class classname<typename>;
顯式執行個體化隻需聲明,不需要重新定義。編譯器根據模闆實作執行個體聲明和執行個體定義。
顯示具體化:
對于某些特殊類型,可能不适合模闆實作,需要重新定義實作,此時可以使用顯示具體化(explicite specialization)。顯示執行個體化需重新定義。格式為:
template<> typename function<typename>(argu_list){...};
template<> class classname<typename>{...};
綜上:
template<> void swap<job>(job &a, job &b) {……};是函數模闆的顯式具體化,意思是job類型不适用于函數模闆swap的定義,是以通過這個顯式具體化重新定義;也可簡寫作template<> void swap(job &a, job &b);
template void swap<job>(job &a, job &b);是函數模闆的一個顯式執行個體化,隻需聲明,編譯器遇到這種顯式執行個體化,會根據原模闆的定義及該聲明直接生成一個執行個體函數,該函數僅接受job型。否則編譯器遇到模闆的使用時才會隐式的生成相應的執行個體函數。