網站首頁 編程語言 正文
一、非模板類型參數
分類:
模板參數分類類型形參與非類型形參
概念:
1.類型形參:
出現在模板參數列表中,跟在class或者typename之類的參數類型名稱
2.非類型形參:
用一個常量作為類(函數)模板的一個參數,在類(函數)模板中可將該參數當成常量來使用
示例:
namespace cole { // 定義一個模板類型的靜態數組 template<class T, size_t N = 10> class array { public: T& operator[](size_t index) { return _array[index]; } const T& operator[](size_t index)const { return _array[index]; } size_t size()const { return _size; } bool empty()const { return 0 == _size; } private: T _array[N]; size_t _size; }; }
注意:
1.浮點數、類對象以及字符串是不允許作為非類型模板參數的
2.非類型的模板參數必須在編譯期就能確認結果
二、模板特化
概念:
使用模板可以實現一些與類型無關的代碼,但對于一些特殊類型的可能會得到一些錯誤的結果
示例:
template<class T> bool IsEqual(const T& left, const T& right) { return left == right; } // 函數模板的特化 (針對某些類型的特殊化處理) //bool IsEqual(const char* const & left,const char* const & right) bool IsEqual(const char* left, const char* right) { return strcmp(left, right) == 0; } int main() { cout << IsEqual(1, 2) << endl; char p1[] = "hello"; char p2[] = "hello"; cout << IsEqual(p1, p2) << endl;; return 0; }
特殊化結果:
?
?不做特殊化結果:
?
注:此時對于字符串比較就需要對模板進行特化(在原模板類的基礎上,針對特殊類型所進行特殊化的實現方式)
特化分類:
函數模板特化與類模板特化
1、函數模板特化
函數模板的特化步驟:
- 必須要先有一個基礎的函數模板
- 關鍵字template后面接一對空的尖括號<>
- 函數名后跟一對尖括號,尖括號中指定需要特化的類型
- 函數形參表: 必須要和模板函數的基礎參數類型完全相同,如果不同編譯器可能會報一些奇怪的錯誤
示例:
template<class T> bool IsEqual(const T left, const T right) { return left == right; } template<> bool IsEqual<char*>(char* left,char* right) { if (strcmp(left, right) == 0) return true; return false; }
結果:
?
注:一般情況下如果函數模板遇到不能處理或者處理有誤的類型,為了實現簡單通常都是將該函數直接給出
示例:
bool IsEqual(char* left, char* right) { if (strcmp(left, right) == 0) return true; return false; }
2、類模板特化
1)全特化
概念:
全特化即是將模板參數列表中所有的參數都確定化
示例:
template<class T1, class T2> class Data { public: Data() { cout << "Data<T1, T2>" << endl; } private: T1 _d1; T2 _d2; }; template<> class Data<int, char> { public: Data() { cout << "Data<int, char>" << endl; } private: int _d1; char _d2; }; void TestVector() { Data<int, int> d1; Data<int, char> d2; }
2)偏特化
概念:
任何針對模版參數進一步進行條件限制設計的特化版本
偏特化有以下兩種表現方式:
1.部分特化
將模板參數類表中的一部分參數特化
示例:
// 將第二個參數特化為inttemplate <class T1>class Data<T1, int>{public:Data() { cout << "Data<T1, int>" << endl; }private:T1 _d1;int _d2;};// 將第二個參數特化為int template <class T1> class Data<T1, int> { public: Data() { cout << "Data<T1, int>" << endl; } private: T1 _d1; int _d2; };
2.參數更進一步的限制
偏特化并不僅僅是指特化部分參數,而是針對模板參數更進一步的條件限制所設計出來的一個特化版本
示例:
//兩個參數偏特化為指針類型template <typename T1, typename T2>class Data <T1*, T2*>{public:Data() { cout << "Data<T1*, T2*>" << endl; }private:T1 _d1;T2 _d2;};//兩個參數偏特化為引用類型template <typename T1, typename T2>class Data <T1&, T2&>{public:Data(const T1& d1, const T2& d2): _d1(d1), _d2(d2){cout << "Data<T1&, T2&>" << endl;}private:const T1& _d1;const T2& _d2;};void test2(){Data<double, int> d1; // 調用特化的int版本Data<int, double> d2; // 調用基礎的模板Data<int*, int*> d3; // 調用特化的指針版本Data<int&, int&> d4(1, 2); // 調用特化的指針版本}//兩個參數偏特化為指針類型 template <typename T1, typename T2> class Data <T1*, T2*> { public: Data() { cout << "Data<T1*, T2*>" << endl; } private: T1 _d1; T2 _d2; }; //兩個參數偏特化為引用類型 template <typename T1, typename T2> class Data <T1&, T2&> { public: Data(const T1& d1, const T2& d2) : _d1(d1) , _d2(d2) { cout << "Data<T1&, T2&>" << endl; } private: const T1& _d1; const T2& _d2; }; void test2() { Data<double, int> d1; // 調用特化的int版本 Data<int, double> d2; // 調用基礎的模板 Data<int*, int*> d3; // 調用特化的指針版本 Data<int&, int&> d4(1, 2); // 調用特化的指針版本 }
三、模板分離編譯
分離編譯概念:
一個程序(項目)由若干個源文件共同實現,而每個源文件單獨編譯生成目標文件,最后將所有目標文件鏈接起來形成單一的可執行文件的過程稱為分離編譯模式
模板分離編譯:
假如有以下場景,模板的聲明與定義分離開,在頭文件中進行聲明,源文件中完成定義
示例:
// a.h template<class T> T Add(const T& left, const T& right); // a.cpp template<class T> T Add(const T& left, const T& right) { return left + right; } // main.cpp #include"a.h" int main() { Add(1, 2); Add(1.0, 2.0); return 0; }
注:以上代碼的模板分離編譯會報錯
分析:?
解決方法
1.將聲明和定義放到一個文件?“xxx.hpp”?(h文件和cpp文件結合)里面或者xxx.h其實也是可以的(推薦)
2.模板定義的位置顯式實例化(不實用)
四、模板總結
優點:
- 模板復用了代碼,節省資源,更快的迭代開發,C++的標準模板庫(STL)因此而產生
- 增強了代碼的靈活性
缺陷:
- 模板會導致代碼膨脹問題,也會導致編譯時間變長(為了盡量減少此類問題,編譯器會按需實例化)
- 出現模板編譯錯誤時,錯誤信息非常凌亂,不易定位錯誤
- 不支持分離編譯
總結
原文鏈接:https://blog.csdn.net/CS_z_jun/article/details/122489790
相關推薦
- 2022-03-16 詳解c#中Array,ArrayList與List<T>的區別、共性與相互轉換_C#教程
- 2023-01-05 淺析C++中的重載,隱藏和覆蓋_C 語言
- 2022-03-03 gyp ERR! configure error. gyp ERR! stack Error: gy
- 2022-04-17 axios token失效刷新token怎么重新請求_Token 刷新并發處理解決方案
- 2022-06-18 Asp.Net?Core配置多環境log4net配置文件的全過程_實用技巧
- 2022-03-26 使用C語言如何輸出逆序數_C 語言
- 2022-06-01 C#的通用DbHelper類(支持數據連接池)示例詳解_C#教程
- 2024-03-13 Linux 安裝RabbitMQ
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支