模板函式的特化
- 模板特化:就是在例項化模板時,對特定型別的實參進行特殊處理,即例項化一個特殊的例項版本,
- 當以特化定義時的形參使用模板時,將呼叫特化版本,模板特化分為全特化和偏特化;
- 1. 函式模板的特化,只能全特化;
- //泛型版本
- template <class T> int compare(const T &v1, const T &v2)
- {
- if(v1 < v2) return -1;
- if(v2 > v1) return 1;
- return 0;
- }
- 對於該函式模板,當實參為兩個char指標時,比較的是指標的大小,而不是指標指向內容的大小,此時就需要為該函式模板定義一個特化版本,即特殊處理的版本:
- //為實參型別 const char * 提供特化版本
- template <> int compare<const char *>(const char * const &v1, const char * const &v2)
- {
- return strcmp(v1, v2);
- }
- a: template <> //空模板形參表
- b: compare<const char *> //模板名字後指定特化時的模板形參即const char *型別,就是說在以實參型別 const char * 呼叫函式時,將產生該模板的特化版本,而不是泛型版本,也可以為其他指標型別定義特化版本如int *.
- c: (const char * const &v1, const char * const &v2)//可以理解為: const char * const &v1, 去掉const修飾符,實際型別是:char *&v1,也就是v1是一個引用,一個指向char型指標的引用,即指標的引用,加上const修飾符,v1就是一個指向const char 型指標的 const引用,對v1的操作就是對指標本身的操作,操作方式與指標一致,比如*v1,是正確的;//注意這裡的const char *, 由於形參是一個指向指標的const引用,所以呼叫特化版本時的實參指標型別(並非儲存的資料的型別)可以為const也可以為非const,但是由於這裡形參指標指向的資料型別為const char *(強調儲存的資料是const),所以實參指標所指向的資料型別也必須為const,否則型別不匹配;
- //特化版本 (int *)
- template <> int compare<const int *>(const int * const &v1, const int * const &v2)//v1 和 v2 是指向const 整形變數的const引用;
- {
- if(*v1 < *v2) return -1;//像指標一樣操作,可以理解v1,v2就是指標,因為它是指標的引用;
- if(*v2 > *v1) return 1;
- }
- 2. 與其他函式宣告一樣,應該在一個標頭檔案中包含模板特化的宣告,在使用特化模板的原始檔中包含該標頭檔案;
- 注意,函式模板呼叫時的實參與模板形參不進行常規轉換,特化與泛型版本都不進行常規轉換,型別必須完全一致,非函式模板在實參呼叫時進行常規轉換;普通函式和函式模板呼叫時的實參與模板形參都進行兩種轉換:
- (1). const轉換:接受const引用或者const指標的函式,可以分別以非const物件的引用或者指標來呼叫,無需產生新例項,如果函式接受非引用型別或者非指標型別,形參型別和實參型別忽略const,無論傳遞const還是非const物件給非引用型別的函式,都使用相同的例項;
- (2). 陣列或函式指標的轉換:如果模板形參不是引用型別,則對陣列或函式型別的實參應用常規轉換,陣列轉換為指向實參第一個元素的指標,函式實參當做指向函式型別的指標;注意:函式模板中,模板形參表中的非型別形參遵循常規轉換原則。
- //例子:
- //16.6.1.h
- #include <stdio.h>
- #include <string.h>
- #include <iostream>
- //泛型版本
- template <typename T> int compare(const T &v1, const T &v2)
- {
- std::cout << "template <typename T>" << std::endl;
- if(v1 < v2) return -1;
- if(v2 < v1) return 1;
- return 0;
- }
- //為實參型別 const char * 提供特化版本
- //template <> int compare(const char * const &v1, const char * const &v2) //省略了函式名後邊的顯示模板實參,因為可以從函式形參表推斷出來,本定義與下邊的定義都是正確的;
- template <> int compare<const char *>(const char * const &v1, const char * const &v2)
- {
- std::cout << "template <> int compare<const char *>" << std::endl;
- return strcmp(v1, v2);
- }
- //為實參型別 char * 提供特化版本
- //template <> int compare(char * const &v1, char * const &v2)
- template <> int compare<char *>(char * const &v1, char * const &v2)
- {
- std::cout << "template <> int compare<char *>" << std::endl;
- return strcmp(v1, v2);
- }
- //16.6.1.cpp
- #include <iostream>
- #include "16.6.1.h"
- using namespace std;
- int main()
- {
- cout << compare(1, 2) << endl; //根據實參型別進行實參推斷,將為該呼叫例項化int compare(int, int)
- char a[] = {"abc"}; //一個普通字元陣列,不是指標,形參為引用時,陣列大小成為形參的一部分,陣列不轉換為指標,型別不匹配;
- const char b[] = {"abc"}; //一個常量字元陣列,不是指標,型別不匹配;
- char *p = "ddd"; //一個非const指標,指向非const資料,但是特化版本的形參型別是一個指向const資料的const引用,強調了指標指向的資料型別是const,也就是說實參指標指向的資料型別必須是const即指標儲存的資料必須是const的,但這裡不是因此型別不匹配;
- char * const pc = "ddd"; //一個const指標,指向非const資料,型別不匹配,原因同上,和指標是否是const沒關係,和指標儲存的資料型別有關;
- const char * const pc = "ddd"; //一個const指標,指向const資料,滿足特化版本的形參(一指向const資料的const引用),型別匹配;
- const char * pc = "ddd"; //一個非const指標,指向const資料,型別匹配,原因同上;
- //為實參型別 const char * 提供特化版本
- const char *pa = "abc"; // 或者 const char * const pa = "abc"; 與指標指向資料型別是const還是非const有關,而與指標是const還是非const沒關係,因為,特化版本的形參型別是一個指向指標的cosnt引用,因此不會改變指標的值,所以指標本身是const還是非cosnt沒有關係,但是由於特化版本形參的引用指向的指標所指向的資料型別是const,所以不能使用一個指向非const資料的指標呼叫特化版本,因為資料型別不匹配;
- const char *pb = "bbd";
- cout << compare(pa, pb) << endl; // 根據實參型別為該呼叫例項化特化版本int compare(const * const &v1, const * const &v2), 函式模板呼叫時的實參與模板形參不進行常規轉換;由於編譯器對特化版本不進行實參與形參的常規轉換,所以呼叫的實參型別必須與特化版本的宣告完全一致,否則將從泛型版本進行例項化,或者函式匹配錯誤;由於compare宣告的形參都是const char *即char *型指標儲存的是const資料,所以不能傳遞一個儲存了非const資料的char *型指標(儘管此時的cosnt char *形參不會改變實參指標指向的值),也不能傳遞一個const陣列名字(此時陣列名不會轉換為指標),必須傳遞一個指向const資料的指標,即程式碼中的 const char *pa,型別必須完全匹配;
- //為實參型別 char * 提供特化版本
- char *pc = "ccc";
- char *pd = "ddd";
- cout << compare(pc, pd) << endl;
- return 0;
- //char * 與 const char * 是兩個不同的資料型別(前者儲存的資料是常量與後者儲存的資料是非常量),雖然可以將型別 char * 通過常規轉換,轉換成 const char *,但是作為模板實參,在模板實參推斷時,不會把函式呼叫時的實參型別 char * 轉換為模板形參型別const char *,所以必須提供兩個特化版本。
- }
- 執行結果:
- template <typename T>
- -1
- template <> int compare<const char *>
- -1
- template <> int compare<char *>
- -1
相關文章
- 進階篇_STL詳解(函式模板特化,類别範本特化,用模板實現自己的通用演算法)函式演算法
- c++泛型程式設計中函式模板過載和模板特化同時存在時的查詢規則C++泛型程式設計函式
- 模板顯式、隱式例項化和(偏)特化、具體化的詳細分析
- 函式模板函式
- C++的函式和模板函式 (轉)C++函式
- Smarty 模板函式函式
- 函式過載與函式模板的區別函式
- c++函式模板C++函式
- 函式模板深探函式
- WordPress模板常用函式函式
- 【模板】生成函式 I函式
- 函式模板過載函式
- C++ 函式過載,函式模板和函式模板過載,選擇哪一個?C++函式
- 模板函式編譯原理函式編譯原理
- 4.C++函式模板C++函式
- C#模擬C++模板特化對型別的值的支援C#C++型別
- C++模板的定製一:定製函式模板 (轉)C++函式
- WordPress模板常用函式彙總函式
- WordPress主題模板層次和常用模板函式函式
- 母函式詳解和史上最通用最高效的母函式模板函式
- 【c++】函式模板的簡單應用C++函式
- 關於C++當中的“模板函式”C++函式
- C++ 函式過載和模板C++函式
- wordpress模板修改及函式說明函式
- [C++] 氣泡排序的模板函式設計C++排序函式
- C++關於DLL匯出模板類和模板函式C++函式
- const char*的全特化
- c++函式模板和類别範本C++函式
- c++函式模板和執行機制C++函式
- c++中的特化問題C++
- 瞭解ES6中的模板字串的標籤函式字串函式
- C++模板函式實現型別推導C++函式型別
- 轉載:尤拉函式知識點總結及程式碼模板及尤拉函式表函式
- 請教,blade模板中怎麼呼叫自定義的函式?函式
- 一種將函式模板定義和宣告分開的方法函式
- 【C++進階筆記】(1)函式模板的宣告及使用C++筆記函式
- 【C++ 泛型程式設計01:模板】函式模板與類别範本C++泛型程式設計函式
- 消除複製建構函式和“模板式複製建構函式”中的冗餘程式碼 (轉)函式