1.模板簡介
模板就是實現代碼重用的一種機制,它可以實現類型參數化,即把類型定義爲參數, 從而實現了真正的代碼可重用性。
模板編程和函數重載可以實現C++靜態多態,也叫編譯時多態。
模版可以分爲兩類,一個是 函數模版 ,另一個是 類模版。
2.模板特化的目的
模板本來是一組通用邏輯的實現,但是可能存在特定的參數類型下,通用的邏輯實現不能滿足要求,這時就需要針對這些特殊的類型,而實現一個特例模板—即模板特化。
3.重點注意
1)類模板和函數模板都可以被全特化;
2)類模板能偏特化,不能被重載;
3)函數模板可以實現重載,不能被偏特化;
4)類模板調用優先級:全特化類>偏特化類>主版本模板類;
5)注意模板編程不支持分離式編譯,即模板類/模板函數的聲明與定義應該放在頭文件裏,否則會在鏈接時報錯;
6)函數模板同時存在具體化模板、函數模板重載、和常規函數重載時候,調用優先級:
常規函數 > 具體化模板函數 > 常規模板函數;
注意:重載決議時,優先決議出是不是符合常規函數,不存在符合的普通函數,纔會再決議出符合的函數主模板,對於函數模板重載決議,會無視特化存在(標準規定:重載決議無視模板特化,重載決議發生在主模板之間),決議出函數主模板後,如果函數主模板存在符合的具體化函數模板,纔會調用具體化函數模板;
7)不能將函數模板特化和重載混爲一談
函數特化都沒有引入一個全新的模板或者模板實例,它們只是對原來的主(或者非特化)模板中已經隱式聲明的實例提供另一種定義。在概念上,這是一個相對比較重要的現象,也是特化區別於重載模板的關鍵之處。
如果使用普通重載函數,那麼不管是否發生實際的函數調用,都會在目標文件中生成該函數的二進制代碼。而如果使用函數模板特化版本,除非發生函數調用,否則不會在目標文件中包含特化模板函數的二進制代碼。這符合函數模板的“惰性實例化”準則。
4.函數模板
1)常規函數
// 常規函數
void Compare(const char* first, const char* second)
{
cout << "const char* ordinary function " << endl;
if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
}
2)函數主模板a
//函數主模板
template<typename T, typename N> void Compare(T first, N second)
{
cout << "Standard function template <T, N>" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
3)函數模本b--全特化
針對char*類型的比較函數,不能直接使用大於號或小於號比較元素,需要特化;
//函數模板-全特化
template<> void Compare(const char* first, const char* second)
{
cout << "const char* specialization <const char*, const char*>" << endl;
if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
}
4)函數模板c-重載,作爲一個獨立的函數主模板
//函數模板-重載,不是偏特化,它會作爲一個獨立的函數主模板
template<typename T, typename N> void Compare(T* first, N* second)
{
cout << "function template overload <T*, N*>" << endl;
cout << "T type: " << typeid(T).name() << ", N type : " << typeid(N).name() << endl;
if (strcmp(typeid(T).name(), "char") == 0 && strcmp(typeid(N).name(), "char") == 0)
{
if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
}
else
{
if (*first < *second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
}
5)函數模板之間的重載決議
【1】當代碼中存在如下順序的申明時,
template<typename T, typename N> void Compare(T first, N second) //函數主模板a
{.....}
template<> void Compare(const char* first, const char* second) // 函數主模板a的全特化模板 b
{.....}
template<typename T, typename N> void Compare(T* first, N* second) // 函數主模板c,是函數主模板a的重載
{.....}
那麼,發生如下函數調用時,
Compare("1", "2");
會打印輸出:
這裏顯示實際調用了函數主模板c,
因爲在調用Compare("1", "2")時,先會進行重載決議,
發生重載決議,會無視特化存在(標準規定:重載決議無視模板特化,重載決議發生在主模板之間),
那麼就會決議出函數主模板c;
【2】當代碼中存在如下順序的申明時,
template<typename T, typename N> void Compare(T first, N second) //函數主模板a
{.....}
template<typename T, typename N> void Compare(T* first, N* second) // 函數主模板b,是函數主模板a的重載
{.....}
template<> void Compare(const char* first, const char* second) // 此時是函數主模板b的全特化模板 ,爲全特化函數模板c
{.....}
那麼,發生如下函數調用時,
Compare("1", "2");
會打印輸出:
這裏顯示實際調用了全特化函數模板c,
因爲在調用Compare("1", "2")時,先會進行重載決議,
發生重載決議,會無視特化存在(標準規定:重載決議無視模板特化,重載決議發生在主模板之間),
那麼就會決議出函數主模板b,在判斷函數主模板存在符合類型條件的全特化模板c
函數模板特化與重載決議
6)常規函數與函數模板之間的重載決議
當代碼中存在如下順序的申明時,
template<typename T, typename N> void Compare(T first, N second) //函數主模板a
{.....}
template<> void Compare(const char* first, const char* second) // 函數主模板a的全特化模板 b
{.....}
template<typename T, typename N> void Compare(T* first, N* second) // 函數主模板c,是函數主模板a的重載
{.....}
void Compare(const char* first, const char* second) // 常規函數
{.....}
那麼,發生如下函數調用時,
Compare("1", "2");
會打印輸出:
這裏顯示實際調用了常規函數,
因爲在調用Compare("1", "2")時,先會進行重載決議,重載決議會優先決議是否存在符合條件的常規函數。
7)函數模板全部實現
/******************************* template function start ****************************************/
//函數主模板
template<typename T, typename N> void Compare(T first, N second)
{
cout << "Standard function template <T, N>" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
cout << endl;
}
//函數模板-全特化
template<> void Compare(const char* first, const char* second)
{
cout << "const char* specialization <const char*, const char*>" << endl;
if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
cout << endl;
}
//函數主模板-重載,不是偏特化,它會作爲一個獨立的函數主模板
template<typename N> void Compare(int first, N second)
{
cout << "partitial specialization <int, N>" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
cout << endl;
}
//函數模板-重載,不是偏特化,它會作爲一個獨立的函數主模板
template<typename T, typename N> void Compare(T* first, N* second)
{
cout << "function template overload <T*, N*>" << endl;
cout << "T type: " << typeid(T).name() << ", N type : " << typeid(N).name() << endl;
if (strcmp(typeid(T).name(), "char") == 0 && strcmp(typeid(N).name(), "char") == 0)
{
if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
}
else
{
if (*first < *second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
cout << endl;
}
//函數主模板-重載,不是偏特化,它會作爲一個獨立的函數主模板
template<typename T, typename N> void Compare(std::vector<T>& first, std::vector<N>& second)
{
cout << "to vector partitial specialization <std::vector,std::vector>" << endl;
if (first.size() < second.size())
{
cout << "first.size() < second.size()" << endl;
}
else
{
cout << "first.size() >= second.size()" << endl;
}
cout << endl;
}
// 常規函數
void Compare(const char* first, const char* second)
{
cout << "const char* ordinary function " << endl;
if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
cout << endl;
}
// 測試函數模板功能
void Test_Temmplate_Function()
{
cout << __FUNCTION__ << ":" << endl;
Compare(1,2);
Compare(1, 2.0);
Compare(1.0, 2.0);
Compare('1', '2');
Compare("1", "2");
vector<int> v1 = { 1 };
vector<int> v2 = { 2 };
Compare(v1, v2);
cout << endl;
}
/******************************* template function end ****************************************/
打印輸出如下圖,
5.類模板
必須先有泛化版本類模板(主模板),纔有特化版本類模板。
1)類模板特化分類
特化爲絕對類型(全特化);
特化爲引用,指針類型(半特化、偏特化);
特化爲另外一個類模板(複雜點的偏特化)
2)類模板-主模板類
//類模板-主版本模板類
template<typename T, typename N> class MyClass
{
public:
void Compare(T first, N second)
{
cout << "standard function template" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
};
3)類模板-全特化(具體化)
//類模板-全特化(具體化)
template<> class MyClass<const char*, const char*>
{
public:
void Compare(const char* first, const char* second)
{
cout << "const char* specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
}
};
4)類模板-特化(部分具體化),對部分模板參數進行特化爲一般類型
//類模板-特化(部分具體化),對部分模板參數進行特化
template<typename N> class MyClass<int, N>
{
public:
void Compare(int first, N second)
{
cout << "partitial specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
};
5)類模板-特化(部分具體化),將模板參數特化爲指針
//類模板-特化(部分具體化),將模板參數特化爲指針
template<typename T, typename N> class MyClass<T*, N*>
{
public:
void Compare(T* first, N* second)
{
cout << "ptr partitial specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
};
6)類模板-特化(部分具體化),將模板參數特化爲另一個模板類
//類模板-特化(部分具體化),將模板參數特化爲另一個模板類
template<typename T, typename N> class MyClass<vector<T>, vector<N>>
{
public:
void Compare(const vector<T>& first, const vector<N>& second)
{
cout << "to vector partitial specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first.size() < second.size())
{
cout << "first.size < second.size" << endl;
}
else
{
cout << "first.size >= second.size" << endl;
}
}
};
7)類模板特化全部實現
/******************************* template class start ****************************************/
//類模板-主版本模板類
template<typename T, typename N> class MyClass
{
public:
void Compare(T first, N second)
{
cout << "standard function template" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
};
//類模板-全特化(具體化)
template<> class MyClass<const char*, const char*>
{
public:
void Compare(const char* first, const char* second)
{
cout << "const char* specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (strcmp(first, second) > 0) // 比較char*,需要區別函數主模板進行處理
{
cout << "first:" << first << " > second:" << second << endl;
}
else
{
cout << "first:" << first << " <= second:" << second << endl;
}
}
};
//類模板-特化(部分具體化),對部分模板參數進行特化
template<typename N> class MyClass<int, N>
{
public:
void Compare(int first, N second)
{
cout << "partitial specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
};
//類模板-特化(部分具體化),將模板參數特化爲指針
template<typename T, typename N> class MyClass<T*, N*>
{
public:
void Compare(T* first, N* second)
{
cout << "ptr partitial specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first < second)
{
cout << "first < second" << endl;
}
else
{
cout << "first >= second" << endl;
}
}
};
//類模板-特化(部分具體化),將模板參數特化爲另一個模板類
template<typename T, typename N> class MyClass<vector<T>, vector<N>>
{
public:
void Compare(const vector<T>& first, const vector<N>& second)
{
cout << "to vector partitial specialization" << endl;
cout << __FUNCTION__ << ":" << endl;
if (first.size() < second.size())
{
cout << "first.size < second.size" << endl;
}
else
{
cout << "first.size >= second.size" << endl;
}
}
};
// 測試類模板功能
void Test_Temmplate_Class()
{
cout << __FUNCTION__ << ":" << endl;
MyClass<char, int> c_i_myclass;
c_i_myclass.Compare(1, 2);
printf("function address: %p\n\n", &MyClass<char,int>::Compare);
MyClass<int, double> i_d_myclass;
i_d_myclass.Compare(1, 2);
printf("function address: %p\n\n", &MyClass<int, double>::Compare);
MyClass<int, int> i_i_myclass1;
i_i_myclass1.Compare(1, 2);
printf("function address: %p\n\n", &MyClass<int, int>::Compare);
MyClass<int, int> i_i_myclass2;
i_i_myclass2.Compare(1, 2);
printf("function address: %p\n\n", &MyClass<int, int>::Compare);
MyClass<const char*, const char*> c_c_c_c_myclass;
c_c_c_c_myclass.Compare("1", "2");
printf("function address: %p\n\n", &MyClass<const char*, const char*>::Compare);
MyClass<vector<int>, vector<char>> vc_i_vc_c_maclass;
vc_i_vc_c_maclass.Compare({ 1 }, { 1,2 });
printf("function address: %p\n\n", &MyClass<vector<int>, vector<char>>::Compare);
cout << endl;
}
/******************************* template class end ****************************************/
執行後打印輸出如下圖所示,
可以看到MyClass<int, int>類型聲明的對象,函數Compare地址是一樣的。