溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

深入分析C++模板特化與偏特化

發(fā)布時間:2020-09-20 12:33:09 來源:腳本之家 閱讀:229 作者:Dabelv 欄目:開發(fā)技術(shù)

1.模板特化

1.1概述

模板特化(template specialization)不同于模板的實例化,模板參數(shù)在某種特定類型下的具體實現(xiàn)稱為模板的特化。模板特化有時也稱之為模板的具體化,分別有函數(shù)模板特化和類模板特化。

1.2函數(shù)模板特化

函數(shù)模板特化是在一個統(tǒng)一的函數(shù)模板不能在所有類型實例下正常工作時,需要定義類型參數(shù)在實例化為特定類型時函數(shù)模板的特定實現(xiàn)版本。查看如下例子。

#include <iostream>
using namespace std;

template<typename T> T Max(T t1,T t2)
{
return (t1>t2)?t1:t2;
}

typedef const char* CCP;
template<> CCP Max<CCP>(CCP s1,CCP s2)
{
return (strcmp(s1,s2)>0)?s1:s2;
}

int main()
{
//調(diào)用實例:int Max<int>(int,int)
int i=Max(10,5);
//調(diào)用顯示特化:const char* Max<const char*>(const char*,const char*)
const char* p=Max<const char*>("very","good");
cout<<"i:"<<i<<endl;
cout<<"p:"<<p<<endl;
}

程序正常編譯運(yùn)行結(jié)果:

i:10
p:very

在函數(shù)模板顯示特化定義(Explicit Specialization Definition)中,顯示關(guān)鍵字template和一對尖括號<>,然后是函數(shù)模板特化的定義。該定義指出了模板名、被用來特化模板的模板實參,以及函數(shù)參數(shù)表和函數(shù)體。在上面的程序中,如果不給出函數(shù)模板Max< T>在T為const char*時的特化版本,那么在比較兩個字符串的大小時,比較的是字符串的起始地址的大小,而不是字符串的內(nèi)容在字典序中先后次序。

除了定義函數(shù)模板特化版本外,還可以直接給出模板函數(shù)在特定類型下的重載形式(普通函數(shù))。使用函數(shù)重載可以實現(xiàn)函數(shù)模板特化的功能,也可以避免函數(shù)模板的特定實例的失效。例如,把上面的模板特化可以改成如下重載函數(shù)。

typedef const char* CCP;
CCP Max(CCP s1,CCP s2)
{
return (strcmp(s1,s2)>0)?s1:s2;
}

程序運(yùn)行結(jié)果和使用函數(shù)模板特化相同。但是,使用普通函數(shù)重載和使用模板特化還是有不同之處,主要表現(xiàn)在如下兩個方面:
(1)如果使用普通重載函數(shù),那么不管是否發(fā)生實際的函數(shù)調(diào)用,都會在目標(biāo)文件中生成該函數(shù)的二進(jìn)制代碼。而如果使用模板的特化版本,除非發(fā)生函數(shù)調(diào)用,否則不會在目標(biāo)文件中包含特化模板函數(shù)的二進(jìn)制代碼。這符合函數(shù)模板的“惰性實例化”準(zhǔn)則。
(2)如果使用普通重載函數(shù),那么在分離編譯模式下,應(yīng)該在各個源文件中包含重載函數(shù)的申明,否則在某些源文件中就會使用模板函數(shù),而不是重載函數(shù)。

1.3類模板特化

類模板特化類似于函數(shù)模板的特化,即類模板參數(shù)在某種特定類型下的具體實現(xiàn)。考察如下代碼。

#include <iostream>
using namespace std;

template<typename T>class A
{
T num;
public:
A()
{
num=T(6.6);
}
void print()
{
cout<<"A'num:"<<num<<endl;
}
};

template<> class A<char*>
{
char* str;
public:
A(){
str="A' special definition ";
}
void print(){
cout<<str<<endl;
}
};

int main()
{
A<int> a1; //顯示模板實參的隱式實例化
a1.print();
A<char*> a2; //使用特化的類模板
A2.print();
}

程序輸出結(jié)果如下:

A'num:6
A' special definition

2.模板偏特化

2.1概述

模板偏特化(template partitial specialization)是模板特化的一種特殊情況,指指定模板參數(shù)而非全部模板參數(shù),或者模板參數(shù)的一部分而非全部特性,也稱為模板部分特化。與模板偏特化相對的是模板全特化,指對所有的模板參數(shù)進(jìn)行特化。模板全特化與模板偏特化共同組成模板特化。

模板偏特化主要分為兩種,一種是指對部分模板參數(shù)進(jìn)行全特化,另一種是對模板參數(shù)特性進(jìn)行特化,包括將模板參數(shù)特化為指針、引用或是另外一個模板類。

2.2函數(shù)模板偏特化

假如我們有一個compare函數(shù)模板,在比較數(shù)值類型時沒有問題,如果傳入的數(shù)值的地址,我們需要兩個數(shù)值的大寫,而非比較傳入的地址大小。此時我們需要對compare函數(shù)模板進(jìn)行偏特化??疾烊缦麓a:

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

//函數(shù)模板
template<typename T, class N> void compare(T num1, N num2)
{
cout << "standard function template" << endl;
if(num1>num2)
cout << "num1:" << num1 << " > num2:" << num2 <<endl;
else
cout << "num1:" << num1 << " <= num2:" << num2 << endl;
}

//對部分模板參數(shù)進(jìn)行特化
template<class N> void compare(int num1, N num2)
{
cout<< "partitial specialization" <<endl;
if (num1>num2)
cout << "num1:" << num1 << " > num2:" << num2 << endl;
else
cout << "num1:" << num1 << " <= num2:" << num2 << endl;
}

//將模板參數(shù)特化為指針
template<typename T, class N> void compare(T* num1, N* num2)
{
cout << "new partitial specialization" << endl;
if (*num1>*num2)
cout << "num1:" << *num1 << " > num2:" << *num2 << endl;
else
cout << "num1:" << *num1 << " <= num2:" << *num2 << endl;
}

//將模板參數(shù)特化為另一個模板類
template<typename T, class N> void compare(std::vector<T>& vecLeft, std::vector<T>& vecRight)
{
cout << "to vector partitial specialization" << endl;
if (vecLeft.size()>vecRight.size())
cout << "vecLeft.size()" << vecLeft.size() << " > vecRight.size():" << vecRight.size() << endl;
else
cout << "vecLeft.size()" << vecLeft.size() << " <= vecRight.size():" << vecRight.size() << endl;
}

int main()
{
compare<int,int>(30,31);//調(diào)用非特化版本compare<int,int>(int num1, int num2)

compare(30,'1'); //調(diào)用偏特化版本compare<char>(int num1, char num2)

int a = 30;
char c = '1';
compare(&a,&c); //調(diào)用偏特化版本compare<int,char>(int* num1, char* num2)

vector<int> vecLeft{0};
vector<int> vecRight{1,2,3};
compare<int,int>(vecLeft,vecRight); //調(diào)用偏特化版本compare<int,char>(int* num1, char* num2)
}

程序輸出結(jié)果如下:

standard function template
num1:30 <= num2:31
partitial specialization
num1:30 <= num2:1
new partitial specialization
num1:30 <= num2:1
to vector partitial specialization
vecLeft.size()1 <= vecRight.size():3

2.3類模板偏特化

類模板的偏特化與函數(shù)模板的偏特化類似??疾烊缦麓a:

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

//類模板
template<typename T, class N> class TestClass
{
public:
static bool comp(T num1, N num2)
{
cout <<"standard class template"<< endl;
return (num1<num2) ? true : false;
}
};

//對部分模板參數(shù)進(jìn)行特化
template<class N> class TestClass<int, N>
{
public:
static bool comp(int num1, N num2)
{
cout << "partitial specialization" << endl;
return (num1<num2) ? true : false;
}
};

//將模板參數(shù)特化為指針
template<typename T, class N> class TestClass<T*, N*>
{
public:
static bool comp(T* num1, N* num2)
{
cout << "new partitial specialization" << endl;
return (*num1<*num2) ? true : false;
}
};

//將模板參數(shù)特化為另一個模板類
template<typename T, class N> class TestClass<vector<T>,vector<N>>
{
public:
static bool comp(const vector<T>& vecLeft, const vector<N>& vecRight)
{
cout << "to vector partitial specialization" << endl;
return (vecLeft.size()<vecRight.size()) ? true : false;
}
};

int main()
{
//調(diào)用非特化版本
cout << TestClass<char, char>::comp('0', '1') << endl; 

//調(diào)用部分模板參數(shù)特化版本
cout << TestClass<int,char>::comp(30, '1') << endl; 

//調(diào)用模板參數(shù)特化為指針版本
int a = 30;
char c = '1';
cout << TestClass<int*, char*>::comp(&a, &c) << endl; 

//調(diào)用模板參數(shù)特化為另一個模板類版本
vector<int> vecLeft{0};
vector<int> vecRight{1,2,3};
cout << TestClass<vector<int>, vector<int>>::comp(vecLeft,vecRight) << endl; 
}

程序輸出結(jié)果:

standard class template
1
partitial specialization
1
new partitial specialization
1
to vector partitial specialization
1

3.模板類調(diào)用優(yōu)先級

對主版本模板類、全特化類、偏特化類的調(diào)用優(yōu)先級從高到低進(jìn)行排序是:全特化類>偏特化類>主版本模板類。這樣的優(yōu)先級順序?qū)π阅芤彩亲詈玫摹?/p>

但是模板特化并不只是為了性能優(yōu)化,更多是為了讓模板函數(shù)能夠正常工作,最典型的例子就是STL中的iterator_traits。algorithm中大多數(shù)算法通過iterator對象來處理數(shù)據(jù),但是同時允許以指針代替iterator對象,這是為了支持C-Style Array。如果直接操作iterator,那么為了支持指針類型,每個算法函數(shù)都需要進(jìn)行重載,因為指針沒有::value_type類型。為了解決這個問題,STL使用了iterator_traits對iterator特性進(jìn)行封裝,并為指針類型做了偏特化處理,算法通過它來操作iterator,不需要知道實際操作的是iterator對象還是指針。

template<typename IteratorClass> class iterator_traits
...
template<typename ValueType> class iterator_traits<ValueType*>
...
template<typename ValueType> class iterator_traits<ValueType const*>
...

后面兩是針對指針類型的偏特化,也是偏特化的一種常見形式。

以上就是深入分析C++模板特化與偏特化的詳細(xì)內(nèi)容,更多關(guān)于C++模板特化與偏特化的資料請關(guān)注億速云其它相關(guān)文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI