C++ - 模板進階

一、非類型模板參數

模板參數? 分為? 類型形參與? 非類型形參
類型形參:出現在模板參數列表中,跟在?class?或者 typename 之類的參數類型名稱
非類型形參,就是用一個常量作為類(函數)模板的一個參數,在類(函數)模板中可將該參數當成常 量來使用
注意:
1.?浮點數、類對象以及字符串是不允許作為非類型模板參數的
2.?非類型的模板參數必須在編譯期就能確認結果。
3. 類型形參 和 非類型形參都可以給缺省值。

?非類型形參有什么用 ??

用宏定義的N 實現的靜態棧對比 :

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stack>
using namespace std;#define N 20template<class T>
class Stack
{
private:T _a[N];int _top;
};int main()
{Stack<int> st1;  //20 return 0;
}

?

此時建立的Stack 的大小只能為N , N如果為 20 , 僅能建立大小為 20 的靜態棧 。如果借助非類型形參? , 則靜態棧建立的大小就變得靈活了

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stack>
using namespace std;template<class T,size_t N>
class Stack
{
private:T _a[N];int _top;
};int main()
{Stack<int,20> st1;  //20 Stack<int, 2000> st2;   //2000return 0;
}

非類型的形參一般來說 , 給整型常量 , 其他的可能不支持 , 浮點常量在C++20支持 。

二、模板的特化

2.1 概念

通常情況下使用模板可以實現一些與類型無關的代碼,但對于一些特殊類型的可能會得到
一些 錯誤的結果,需要特殊處理,比如:實現了一個專門用來進行小于比較的函數模板
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stack>
using namespace std;class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d);
private:int _year;int _month;int _day;
};ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}// 函數模板 -- 參數匹配
template<class T>
bool Less(T left, T right)
{return left < right;
}
int main()
{cout << Less(1, 2) << endl; // 可以比較,結果正確Date d1(2022, 7, 7);Date d2(2022, 7, 8);cout << Less(d1, d2) << endl; // 可以比較,結果正確Date* p1 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl; // 可以比較,結果錯誤return 0;
}

可以看到,Less絕對多數情況下都可以正常比較,但是在? 特殊場景下? 就得到錯誤的結果。上述示 例中,p1指向的d1顯然小于p2指向的d2對象,但是Less內部并沒有比較p1和p2指向的對象內
而比較的是p1和p2指針的地址, 這就無法達到預期而錯誤。

?

此時 , 就需要對模板進行特化 , 即 : 在原模板類的基礎上 , 針對特殊類型所進行特殊化的實現方式 。 模板特化中分為函數模板特化 與 類模板特化 。

2.2 函數模板特化

函數模板特化的步驟:

  • 必須要有一個基礎的函數模板
  • 關鍵字?template? 后面接 一對 空的尖括號 <>
  • 函數名?后跟一對尖括號 , 尖括號中指定需要特化的類型
  • 函數形參表 : 必須要和模板函數的基礎參數類型完全相同 , 如果不同編譯器可能會報一些奇怪的錯誤 。?
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stack>
using namespace std;class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d);
private:int _year;int _month;int _day;
};ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}// 函數模板 -- 參數匹配
template<class T>
bool Less(T left, T right)
{return left < right;
}
// 對Less函數模板進行特化
template<>
bool Less<Date*>(Date* left, Date* right)
{return *left < *right;
}
int main()
{cout << Less(1, 2) << endl;Date d1(2022, 7, 7);Date d2(2022, 7, 8);cout << Less(d1, d2) << endl;Date* p1 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl; // 調用特化之后的版本,而不走模板生成了return 0;
}

注意 : 一般情況下 如果函數模板遇到? 不能處理 或者 處理有誤 的類型 , 為了實現簡單通常都是將函數直接給出 。??

?

bool Less(Date* left, Date* right)
{
return *left < *right;
}

?該種實現簡單明了 , 代碼的可讀性高 , 容易書寫 因為對于一些參數類型復雜的函數模板 , 特化時會比較復雜?。?因此函數模板不建議特化 。?

2.3 類模板特化

2.3.1 全特化

全特化即是將? 模板參數列表中? 所有的參數都確定化。

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stack>
using namespace std;class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d);
private:int _year;int _month;int _day;
};ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}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.3.2 偏特化?

1) 任何針對模版參數進一步進行 條件限制 設計的特化版本。:
template<class T1, class T2>
class Data
{
public:Data() { cout << "Data<T1, T2>" << endl; }
private:T1 _d1;T2 _d2;
};//兩個參數偏特化為指針類型
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); // 調用特化的指針版本
}

?

2)部分特化:將模板參數類表中的? 一部分參數? 特化
template<class T1, class T2>
class Data
{
public:Data() { cout << "Data<T1, T2>" << endl; }
private:T1 _d1;T2 _d2;
};// 將第二個參數特化為int
template <class T1>
class Data<T1, int>
{
public:Data() { cout << "Data<T1, int>" << endl; }
private:T1 _d1;int _d2;
};

?

三、模板分離編譯

3.1 什么是分離編譯

一個程序(項目)由若干個源文件共同實現,而每個源文件單獨編譯生成目標文件 , 最后將所有目標文件鏈接起來形成單一的可執行文件的過程稱為分離編譯模式 。?

3.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;
}

為什么鏈接錯誤 ? (通常是指有聲明無定義)?

3.3 解決方法

?1. 將聲明和定義放到一個文件 “ xxx.hpp ” 里面 或者 xxx.h 其實也是可以的 。(推薦)

?2. 模板定義的位置顯示實例化 。 這種方法不實用,不推薦使用 。?

3.4 模板總結

【優點】?

  1. 模板復用了代碼,節省資源,更快迭代開發,C++的標準模板庫(STL)因此產生。
  2. 增強了代碼的靈活性

【缺點】

  1. 模板會導致代碼膨脹問題,也會導致編譯時間變長
  2. 出現模板編譯錯誤時,錯誤信息非常凌亂,不易定位錯誤

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/916194.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/916194.shtml
英文地址,請注明出處:http://en.pswp.cn/news/916194.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【質量管理】軟件缺陷管理實施方案(專業版)

引言 方案目標與范圍 本方案以CMMI量化管理要求與ISO 9000質量體系為框架,核心目標是通過標準化缺陷管理流程實現缺陷全生命周期可控。具體包括:確保軟件缺陷在全生命周期中被及時發現與修復,減少其對軟件質量、發布計劃及用戶體驗的負面影響;以“零缺陷”為首要目標,針對…

Elasticsearch 講解及 Java 應用實戰:從入門到落地

在數據量爆炸的今天&#xff0c;傳統數據庫的查詢能力越來越難以滿足復雜的檢索需求。比如電商平臺的商品搜索&#xff0c;需要支持關鍵詞模糊匹配、多條件篩選、熱門度排序等功能&#xff0c;這時候 Elasticsearch&#xff08;簡稱 ES&#xff09;就成了最佳選擇。作為一款分布…

docker pull weaviate 國內拉取失敗的問題

我是校內網&#xff0c;嘗試了 改鏡像源 (cooragent) ruiyCJQ:~/sdb/B/cooragent$ sudo vim /etc/docker/daemon.json [sudo] password for ruiy: (cooragent) ruiyCJQ:~/sdb/B/cooragent$ sudo service docker restart (cooragent) ruiyCJQ:~/sdb/B/cooragent$ sudo docke…

Vue項目使用Univer Sheets

Univer Excel主頁鏈接&#xff1a;安裝步驟 1. 安裝 使用預設模式的包管理器安裝 - 預設模式&#xff1a;可以理解為開包即用的模式&#xff0c;省去很多配置&#xff0c;當然自由度不如插件模式 pnpm add univerjs/presets univerjs/preset-sheets-core2. 前端代碼 <te…

Python day24

浙大疏錦行 python day24 內容&#xff1a; 元組&#xff1a;類比于列表&#xff0c;不過元組的元素不能被修改&#xff0c;顯示也是從[]改為了()&#xff0c;其余操作則是和列表類似&#xff0c;且元組是有序的可迭代對象&#xff1a;即可以使用迭代器訪問的對象&#xff0c…

Three.js 動畫系統入門:Tween.js 與 AnimationMixer 的使用

引言 動畫是 Three.js 中增強 3D 場景動態效果的核心技術&#xff0c;能夠為用戶帶來沉浸式體驗。Three.js 支持通過 Tween.js 實現簡單的屬性動畫&#xff0c;以及通過 AnimationMixer 處理復雜的混合動畫和骨骼動畫。本文將深入探討如何使用 Tween.js 控制 Object3D 的屬性動…

裝修進度管理系統功能對比:主流工具9選

本文分享了9款常用的裝修進度管理軟件&#xff0c;包括&#xff1a;1.Worktile&#xff1b;2.中望軟件&#xff1b;3.三維家&#xff1b;4.Procore&#xff1b;5.易達裝修管理系統&#xff1b;6.裝修管家&#xff1b;7.Zoho Projects&#xff1b;8.中建君聯&#xff1b;9.一品裝…

深度學習篇---預訓練模型

在深度學習中&#xff0c;預訓練模型&#xff08;Pretrained Model&#xff09; 是提升開發效率和模型性能的 “利器”。無論是圖像識別、自然語言處理還是語音識別&#xff0c;預訓練模型都被廣泛使用。下面從概念、使用原因、場景、作用等方面詳細介紹&#xff0c;并結合 Pyt…

Redis ①⑦-分布式鎖

分布式鎖 分布式鎖是鎖的一種&#xff0c;都是為了解決多線程/多進程環境下&#xff0c;對共享資源的訪問沖突問題。 不過&#xff0c;像 Java 的 synchronized 或者 C 的 mutex 這種鎖&#xff0c;都是進程內的鎖&#xff0c;而分布式鎖則是跨越進程/機器的鎖。也就是可以針對…

OpenCV-圖像預處理?【圖像顏色空間轉換、灰度化實驗、二值化處理、鏡像翻轉 和 仿射變換】

文章目錄先言一、圖像顏色空間轉換1.RGB顏色空間2.顏色加法3.顏色加權加法4.HSV顏色空間5.圖像轉換&#xff08;cvtColor()&#xff09;二、灰度實驗1.灰度圖2.圖像灰度化&#xff08;最大值法&#xff09;3.圖像灰度化&#xff08;平均值法&#xff09;4.圖像灰度化&#xff0…

APP逆向 day9 安卓開發基礎

一.前言 app逆向當然要學安卓基礎啦&#xff01;今天我們來教安卓基礎當然&#xff0c;安卓基礎不會教的很多&#xff0c;比java還要少&#xff0c;還是那句話&#xff0c;了解就好。 二.安卓環境搭建 2.1 安卓介紹 如果做安卓開發 需要會java代碼安卓SDK(安卓提供的內置…

Jmeter的元件使用介紹:(三)配置元件詳解02

六、計數器 可以用來做一些變量自增操作。 1、Starting value:定義初始值 2、遞增&#xff1a;定義每次執行遞增多少 3、Maximum value:定義承受的最大值 4、數據格式&#xff1a;可以不填&#xff0c;也可以定義成000;001;002等等任意格式都行。&#xff08;1&#xff09;如…

JavaWeb學習打卡15(JSP標簽、JSTL標簽、EL表達式)

EL表達式&#xff1a;${ }獲取數據執行運算獲取web開發的常用對象在pom.xml 文件中導入JSP、JSTL相關依賴&#xff1a;<!--JSP依賴--><!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api --><dependency><groupId>java…

7.22數據結構——順序表

文章目錄一、思維導圖二、實現順序表的功能代碼head.htest.cmain.c一、思維導圖 二、實現順序表的功能代碼 head.h #ifndef __HEAD_H__ #define __HEAD_H__#include <stdio.h> #include <string.h> #include <stdlib.h> //數組的最大長度 #define MAXSIZE …

【如何無限制免費試用 IDEA || Pycharm(JB 全家桶)】

如何無限制免費試用 IDEA || Pycharm(JB 全家桶) 一、目標:解決 JB 全家桶試用時長痛點 如果你是程序員,大概率用過 JetBrains 家的 IDE——IDEA 寫 Java、Pycharm 寫 Python、WebStorm 做前端,體驗確實頂流,但官方 30 天試用到期后,動輒幾千的年費實在讓人肉痛。 咱…

Qt(資源庫和按鈕組)

這一節是對上一節的補充&#xff0c;上一節提到QLabel類和QAabstractButton類&#xff0c;這節內容&#xff1a;1.如設置資源庫&#xff0c;使用資源設置圖片2. 使用按鈕組管理多個按鈕。一、資源庫1. 資源庫作用Qt的資源庫&#xff08;Resource System&#xff0c;.qrc文件&am…

一道檢驗編碼能力的字符串的題目

#include<iostream> #include<vector> #include<string> using namespace std; int bNum0,gNum0; int findEnd(string& s,int si){int lens.size();//當前字母在哪個字符串中,存入comp中string comp;if(s[si]b||s[si]o||s[si]y){comp"boy";bNu…

UniApp X 網絡請求避坑指南:從 JS 到 UTS 的 JSON 數據處理全解析

在 UniApp 開發中&#xff0c;我們經常需要通過 uni.request 獲取服務器返回的 JSON 數據&#xff0c;并將其綁定到頁面或進行邏輯處理。但在 UniApp X&#xff08;基于 UTS&#xff09; 中&#xff0c;由于引入了 強類型語言特性&#xff0c;處理 JSON 數據的方式與 JS 有明顯…

iOS 網絡請求常用依賴庫與系統自帶 API 介紹與示例

iOS 網絡請求常用依賴庫與系統自帶 API 介紹與示例 在 iOS 開發中&#xff0c;進行網絡請求是幾乎所有應用都不可或缺的功能。開發者有多種選擇來處理網絡通信&#xff0c;從系統自帶的 URLSession 到各種流行的第三方庫。下面我將為您介紹 URLSession、AFNetworking、Alamofir…

JavaScript 中 let 在循環中的作用域機制解析

一、let在循環中的特殊性 let作為ES6引入的塊級作用域聲明&#xff0c;在循環結構中存在特殊行為&#xff0c;其核心區別于var的函數作用域特性。理解這一特性對于編寫正確的閉包邏輯至關重要。 在 ECMAScript 規范里&#xff0c;let聲明的變量具有塊級作用域特性&#xff0c;這…