模板作為C++泛型編程的基礎十分重要,其使得一份代碼能用於處理多種數據類型。而有些時候,我們會希望對一些特定的數據類型執行不同的代碼,這時就需要使用模板特例化(template specialization)。 函數模板特例化 首先說一個重要的,函數模板的特例化並不是函數重載,每一個特例化實際上是提 ...
模板作為C++泛型編程的基礎十分重要,其使得一份代碼能用於處理多種數據類型。而有些時候,我們會希望對一些特定的數據類型執行不同的代碼,這時就需要使用模板特例化(template specialization)。
函數模板特例化
首先說一個重要的,函數模板的特例化並不是函數重載,每一個特例化實際上是提供了另一個模板定義式,因此特例化不影響函數匹配。
特例化一個函數模板時,必須為模板中的每個參數都給出實參,關鍵字template後跟一個<>
類模板特例化
類模板中,提供所有實參時叫做全特化,類模板的全特化和函數模板的特例化上沒有什麼不同(除了一個是類模板一個是函數模板:D)
與函數模板必須為每個模板參數提供實參不同,類模板支持部分特例化,也叫偏特化(partial specialization)
當定義類模板的偏特化版本時,模板參數只需包含原模板中那些還未確定類型的模板參數,在類名之後需要添加<>,且需要按對應位置填入實參。
template<typename T, typename P>
class test {
public:
test() { cout << "這是未特化的類模板\n"; }
};
template<typename P>//T被特化為bool類型,template<>中無需typename T
class test<bool,P> {
public:
test() { cout << "這是bool偏特化的類模板\n"; }
};
template<>//全特化,template<>可以為空
class test<int*, int*> {
public:
test(){ cout << "這是接受兩個指針類型的全特化的類模板\n"; }
};
{
test<int*, int> t1;//會調用未特化的類模板
test<bool,int> t2;//會調用bool偏特化
test<int*, int*> t3;//全特化版本
}
#include <iostream>
using namespace std;
template<typename T>
class MyVector {
public:
MyVector<T>() { cout << "MyVector<T>()" << endl; }
};
//針對 char * 模板特例化
template<>
class MyVector<char *> {
public:
MyVector() { cout << "MyVector<char *>" << endl; }
};
//模板特例化,只針對指針類型提供的部分特例化,只知道指針,但是什麼指針不知道
template<typename Ty>
class MyVector<Ty*> {
public:
MyVector() { cout << "MyVector<Ty *>" << endl; }
};
//template<>
//class MyVector<int(*)(int, int)> {
//public:
// MyVector() { cout << "int (*)(int,int )" << endl; }
//
//};
//template<typename T>
//class MyVector<T(*)(T, T)> {
//public:
// MyVector() { cout << "MyVector<T(*)(T, T)>" << endl; }
//
//};
//
//template<typename R1, typename R2, typename R3>
//class MyVector<R1(*)(R2, R3)> {
// public:
// MyVector() { cout << "MyVector<R1(*)(R2, R3)>" << endl; }
//
//};
//template<typename R1, typename R2, typename R3>
//class MyVector<R1(R2, R3)> {
// public:
// MyVector() { cout << "MyVector<R1(R2, R3)>" << endl; }
//
//};
int sum(int x, int y) {
return x + y;
}
int main() {
MyVector<int> v1; //預設模板
MyVector<char *> v2;// char * 特例化模板
MyVector<int *> v3;// 使用部分特例化 class MyVector<Ty*>
MyVector<int (*)(int,int)> v4; // 使用部分特例化 class MyVector<Ty*> ,int (*)(int,int) 指向函數的指針
// 如何針對 MyVector<int (*)(int,int)> v4;寫一個完全特例化版本? 寫法如下
/*
template<>
class MyVector<int(*)(int, int)> {
public:
MyVector() { cout << "int (*)(int,int )" << endl; }
};
*/
// 如何針對 MyVector<int (*)(int,int)> v4;寫一個部分特例化版本? 寫法如下 兩種
/* 寫法1
MyVector 元素是函數指針,返回類型是R1,兩個參數類型分別是R2,R3 提供部分特例化
template<typename T>
class MyVector<T(*)(T, T)> {
public:
MyVector() { cout << "MyVector<T(*)(T, T)>" << endl; }
};
*/
/*
寫法2
MyVector 元素是函數指針,返回類型是R1,兩個參數類型分別是R2,R3 提供部分特例化
template<typename R1, typename R2, typename R3>
class MyVector< R1(*)(R2, R3) >
{
public:
MyVector() { cout << "MyVector<R1(*)(R2, R3)>" << endl; }
};
*/
MyVector<int(int, int)> v5; //元素是函數對象類型,使用預設的函數版本,也可以使用如下方式
/*
template<typename R1, typename R2, typename R3>
class MyVector<R1(R2, R3)>//針對函數類型,進行部分特例化,有一個返回值,有兩個形參
{
public:
MyVector() { cout << "MyVector<R1(R2, R3)>" << endl; }
};
*/
//函數指針類型
typedef int (*PFUNCTION) (int, int);
PFUNCTION pf1 = sum;
pf1(12, 13);
//函數類型
typedef int PFUNCTION2 (int, int);
PFUNCTION2 * pf2 = ∑
(*pf2)(12, 13);
system("pause");
//有完全特例化能匹配就用完全特例化版本,有部分特例化版本就用部分特例化,再沒有就用預設模板
return 0;
}
//問題:這種寫法可以,但是 typename T 這種方式 範圍太大了!!優化如下
template<typename T>
void function(T _t) {
cout << typeid(T).name() << endl;
}
template<typename R, typename R1, typename R2>
//細分到可以取出返回值類型R1,形參1類型R2,形參2類型R3 還可以繼續細分 如下
void function(R1(*)(R2,R3)) {
cout << typeid(R1).name() << endl;
cout << typeid(R2).name() << endl;
cout << typeid(R3).name() << endl;
}
//效果,繼續細分到可以取出返回值類型R1,哪個類類型T,形參1類型R1,形參2類型R2 Good
template<typename R, typename T, typename R1, typename R2>
void function3(R1(T::*)(R2, R3)) {
cout << typeid(T).name() << endl;
cout << typeid(R1).name() << endl;
cout << typeid(R2).name() << endl;
cout << typeid(R3).name() << endl;
}
class Test {
public:
int sum(int x, int y) { return x + y; }
};
int main() {
function3(&Test::sum);
}