C++入門小館: 模板

嘿,各位技術潮人!好久不見甚是想念。生活就像一場奇妙冒險,而編程就是那把超酷的萬能鑰匙。此刻,陽光灑在鍵盤上,靈感在指尖跳躍,讓我們拋開一切束縛,給平淡日子加點料,注入滿滿的passion。準備好和我一起沖進代碼的奇幻宇宙了嗎?Let's go!

我的博客:yuanManGan

我的專欄:C++入門小館?C言雅韻集?數據結構漫游記? 閑言碎語小記坊?題山采玉?領略算法真諦

目錄

模板:

1.泛型編程:

2.函數模板

2.1函數模板概念:

2.2函數模板格式:

2.3 函數模板的原理

2.4 函數模板的實例化

1.隱式實例化:

2. 顯式實例化:

2.5 模板參數的匹配原則

3. 類模板

3.1 類模板的定義格式

3.2 類模板的實例化

4. 非類型模板參數

5.模板的特化

5.1函數模板的特化:

5.2類模板特化

5.2.1全特化

5.2.2?偏特化

6 模板分離編譯

7. 模板總結


模板:

1.泛型編程:

我們為什么要出現模板呢?

我們來看看下列個這個函數:

void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}
void Swap(double& left, double& right)
{double temp = left;left = right;right = temp;
}
void Swap(char& left, char& right)
{char temp = left;left = right;right = temp;
}
......

我們要實現交換,難道寫無數個類型的組合?

這里用函數重載有很多缺點:

代碼的可維護性差,多一個類型就要多寫幾個對應的代碼,復用率低

那我們是否可以告訴編譯器一個模子,讓編譯器自動生成對應的函數呢?

模板又分為函數模板和類模板:

2.函數模板

2.1函數模板概念:

函數模板代表了一個函數家族,該函數模板與類型無關,在使用時被參數化,根據實參類型產生
函數的特定類型版本。

2.2函數模板格式:

template<typename T1, typename T2, ......, typename Tn>
返回值類型? 函數名(參數列表){ }

注意: typename 用來定義模板參數 關鍵字 也可以使用 class( 切記:不能使用 struct 代替
class)

2.3 函數模板的原理

在編譯器的編譯階段,對于函數模板的使用,編譯器需要根據傳入的實參類型來推演生成對應類型的函數以供調用。比如:當用double類型使用函數模板時,編譯器通過對實參類型的推演,T確定為double類型,然后產生一份專門處理double類型的代碼,對于字符類型也是如此。

2.4 函數模板的實例化

用不同類型的參數使用函數模板時 ,稱為函數模板的 實例化 。模板參數實例化分為: 隱式實例化
和顯式實例化
1.隱式實例化:
讓編譯器根據實參推演模板參數的實際類型

?該語句不能通過編譯,因為在編譯期間,當編譯器看到該實例化時,需要推演其實參類型
?通過實參a1將T推演為int,通過實參d1將T推演為double類型,但模板參數列表中只有一個T,
?編譯器無法確定此處到底該將T確定為int 或者 double類型而報錯注意:在模板中,編譯器一般不會進行類型轉換操作,因為一旦轉化出問題,編譯器就需要背黑鍋

此時有兩種處理方式:1. 用戶自己來強制轉化 2. 使用顯式實例化?
Add(a1, (int)d1);
2. 顯式實例化:
在函數名后的 <> 中指定模板參數的實際類型

如果類型不匹配,編譯器會嘗試進行隱式類型轉換,如果無法轉換成功編譯器將會報錯

2.5 模板參數的匹配原則

1. 一個非模板函數可以和一個同名的函數模板同時存在,而且該函數模板還可以被實例化為這
個非模板函數
我們的模板就是自己做飯吃,而非模板函數就是外賣(現成),你媽要出去,給了你錢,你會選擇自己做飯吃還是點外面呢?廢話點外賣啊!
當外面顯式實例化后就變成了,你媽知道你要點外賣,就跟你說,兒啊不要點外賣吃,你點外賣我回來打死你,你就只能自己做飯吃了。
2. 對于非模板函數和同名函數模板,如果其他條件都相同,在調動時會優先調用非模板函數而
不會從該模板產生出一個實例。如果模板可以產生一個具有更好匹配的函數, 那么將選擇模
3. 模板函數不允許自動類型轉換,但普通函數可以進行自動類型轉換

3. 類模板

3.1 類模板的定義格式

template<class T1, class T2, ..., class Tn>
class 類模板名
{
// 類內成員定義
};
#include<iostream>
using namespace std;
// 類模版
template<typename T>
class Stack
{
public:Stack(size_t capacity = 4){_array = new T[capacity];_capacity = capacity;_size = 0;}void Push(const T& data);
private:T* _array;size_t _capacity;size_t _size;
};
// 模版不建議聲明和定義分離到兩個文件.h 和.cpp會出現鏈接錯誤,具體原因后面會講
template<class T>
void Stack<T>::Push(const T& data)
{// 擴容_array[_size] = data;++_size;
}
int main()
{Stack<int> st1; // intStack<double> st2; // doublereturn 0;
}

在STL中大量使用類模板。

3.2 類模板的實例化

類模板實例化與函數
模板實例化不同, 類模板實例化需要在類模板名字后跟 <> ,然后將實例化的
類型放在 <> 中即可,類模板名字不是真正的類,而實例化的結果才是真正的類
// Stack是類名,Stack<int>才是類型
Stack<int> st1; // int
Stack<double> st2; // double

4. 非類型模板參數

先看看下面的

假如我們要創建a1的存儲空間為100,a2的存儲空間為50。但我們實例化出來的對象它的存儲空間依舊是N,我們只能將就內存大的,這時就會出現空間浪費。那有沒有方法我們能自己控制N是多少呢?有的兄弟有的:

模板參數分為類型形參與非類型形參

類型形參即:出現在模板參數列表中,跟在class或者typename之類的參數類型名稱。

非類型形參,就是用一個常量作為類(函數)模板中可將改參數當成常量來使用。

非類型形參就可以解決這個問題:

那有沒有什么實例用到了這個呢?

有的,就是動態數組array

這里沒有尾部插入刪除。因為我們可以直接通過下標訪問最后的元素。

那你說這個和 array<int, 100> a?和 int a[100]有什么區別呢?

有人說array可以自定義類型比如:

array<string, 100> a;

那我問你,數組不能這樣嗎:

string a[20];

那我用vector不是更香嗎?

array和靜態數組沒有什么本質區別,非要說區別就是array有迭代器,但靜態數組也可以使用范圍for,本質的類型的轉換,然后,array對越界的檢查更嚴格:

越界讀越界訪問
靜態數組不報錯抽查報錯
array報錯報錯
注意:
1. 浮點數、類對象以及字符串是不允許作為非類型模板參數的
2. 非類型的模板參數必須在編譯期就能確認結果

5.模板的特化

我們看看下面的代碼:

通常情況下, 使用模板可以實現一些與類型無關的代碼,但對于一些特殊類型的可能會得到一些
錯誤的結果 ,需要特殊處理,比如:實現了一個專門用來進行小于比較的函數模板

我們比較指針的時候是無法比較出我們想要的結果,那我們該怎么做呢,可以在Date類里面重載一下比較運算符當傳入的是指針的時候特殊處理一下。

那我們就是不想改變原類呢,怎么在模板上進行修改呢?

這里就可以使用我們的模板的特化。即:在原模板類的基礎上,針對特殊類型所進行特殊化的實現方。模板特化中分為函數模板特化類模板特化

5.1函數模板的特化:

函數模板的特化步驟:
1. 必須要先有一個基礎的函數模板
2. 關鍵字 template 后面接一對空的尖括號 <>
3. 函數名后跟一對尖括號,尖括號中指定需要特化的類型
4. 函數形參表 :? 必須要和模板函數的基礎參數類型完全相同,如果不同編譯器可能會報一些奇
怪的錯誤。

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

?直接寫函數比寫模板的特化要舒服很多。

bool Less(Date* left, Date* right)
{return *left < *right;
}
該種實現簡單明了,代碼的可讀性高,容易書寫,因為對于一些參數類型復雜的函數模板,特化
時特別給出,因此函數模板不建議特化。

5.2類模板特化

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

這全特化出來的對象就和非模板函數和模板函數的關系一樣,有更匹配的調用更匹配的,沒有就匹配的就調用模板重新創建一個。

5.2.2?偏特化
偏特化:任何針對模版參數進一步進行條件限制設計的特化版本。比如對于以下模板類
template<class T1, class T2>
class Data
{
public:Data() { cout << "Data<T1, T2>" << endl; }
private:T1 _d1;T2 _d2;
};
部分特化:

我們可以對其中一個或多個參數特化

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

參數限制:

還可以指定傳入的類型,比如傳入指針就走這種類型:

//兩個參數偏特化為指針類型
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;
};

6 模板分離編譯

我們之前學習STL時說過使用了模板之后的類的函數聲明和定義最好不要分離。

我們先來了解一下這些:

這個是我們之前學習c語言時可能會困惑的問題,如果在頭文件寫聲明和定義會出現鏈接報錯。

因為在符號表中會重復包含add函數,test.cpp和func.cpp共用一個符號表。我們可以將聲明和定義分離到不同的頭文件,或者將函數靜態不出現在符號表。

我們將聲明的定義分離是怎么實現的呢,這里再來回顧一下:

7. 模板總結

【優點】
1. 模板復用了代碼,節省資源,更快的迭代開發, C++ 的標準模板庫 (STL) 因此而產生
2. 增強了代碼的靈活性
【缺陷】
1. 模板會導致代碼膨脹問題,也會導致編譯時間變長
2. 出現模板編譯錯誤時,錯誤信息非常凌亂,不易定位錯誤

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

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

相關文章

強化學習之基于無模型的算法之基于值函數的深度強化學習算法

3、基于值函數的深度強化學習算法 1&#xff09;深度Q網絡&#xff08;DQN&#xff09; 核心思想 DQN是一種將Q學習與深度神經網絡結合的方法&#xff0c;用于解決高維狀態空間的問題。 它以環境的狀態作為輸入&#xff0c;通過神經網絡輸出每個動作的 Q 值&#xff0c;智能體…

網絡規劃和設計

1.結構化綜合布線系統包括建筑物綜合布線系統PDS&#xff0c;智能大夏布線系統IBS和工業布線系統IDS 2.GB 50311-2016綜合布線系統工程設計規范 GB/T 50312-2016綜合布線系統工程驗收規范 3.結構化布線系統分為6個子系統&#xff1a; 工作區子系統&#xff1b;水平布線子系…

軟件設計師-錯題筆記-計算機硬件和體系

1. 解析&#xff1a;循環冗余校驗碼也叫CRC校驗碼&#xff0c;其中運算包括了模2&#xff08;異或&#xff09;來構造校驗位。別的三種沒有用到模2的方法。 2. 解析&#xff1a;如果是正數&#xff0c;則是首位為0&#xff0c;其余位全為1&#xff0c;這時最大數(2^(n-1))-1…

OpenCV 4.7企業級開發實戰:從圖像處理到目標檢測的全方位指南

簡介 OpenCV作為工業級計算機視覺開發的核心工具庫,其4.7版本在圖像處理、視頻分析和深度學習模型推理方面實現了顯著優化。 本文將從零開始,系統講解OpenCV 4.7的核心特性和功能更新,同時結合企業級應用場景,提供詳細代碼示例和實戰項目,幫助讀者掌握從基礎圖像處理到復…

LeetCode算法題 (除自身以外數組的乘積)Day14!!!C/C++

https://leetcode.cn/problems/product-of-array-except-self/description/ 一、題目分析 給你一個整數數組 nums&#xff0c;返回 數組 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘積 。 題目數據 保證 數組 nums之中任意元素的全部前綴…

如何寫好Verilog狀態機

還記得之前軟件的同事說過的一句話。怎么凸顯自己的工作量&#xff0c;就是自己給自己寫BUG。 看過夏宇聞老師書的都知道&#xff0c;verilog的FSM有moore和mealy,然后有一段&#xff0c;二段&#xff0c;三段式。記得我還是學生的時候&#xff0c;看到這里的時候&#xff0c;感…

晶振頻率/穩定度/精度/溫度特性的深度解析與測量技巧

在電子設備的精密世界里&#xff0c;晶振如同跳動的心臟&#xff0c;為各類系統提供穩定的時鐘信號。晶振的頻率、穩定度、精度以及溫度特性&#xff0c;這些關鍵參數不僅決定了設備的性能&#xff0c;更在不同的應用場景中發揮著至關重要的作用。 一、頻率選擇的本質&#xff…

Kafka-可視化工具-Offset Explorer

安裝&#xff1a; 下載地址&#xff1a;Offset Explorer 安裝好后如圖&#xff1a; 1、下載安裝完畢&#xff0c;進行新增連接&#xff0c;啟動offsetexplorer.exe&#xff0c;在Add Cluster窗口Properties 選項下填寫Cluster name 和 kafka Cluster Version Cluster name (集…

LabVIEW模板之溫度監測應用

這是一個溫度監測應用程序&#xff0c;基于 Continuous Measurement and Logging 示例項目構建&#xff0c;用于讀取模擬溫度值&#xff0c;當溫度超出給定范圍時發出警報 。 這個。 詳細說明 運行操作&#xff1a;直接運行該 VI 程序。點擊 “Start” 按鈕&#xff0c;即可開…

后端[特殊字符][特殊字符]看前端之Row與Col

是的&#xff0c;在 Ant Design 的柵格布局系統中&#xff0c;每個 <Row> 組件確實對應頁面上的一個獨立行。以下是更詳細的解釋&#xff1a; 核心概念 組件作用類比現實場景<Row>橫向容器&#xff0c;定義一行內容類似 Excel 表格中的一行<Col>縱向分割&am…

[特殊字符] SpringCloud項目中使用OpenFeign進行微服務遠程調用詳解(含連接池與日志配置)

&#x1f4da; 目錄 為什么要用OpenFeign&#xff1f; 在cart-service中整合OpenFeign 2.1 引入依賴 2.2 啟用OpenFeign 2.3 編寫Feign客戶端 2.4 調用Feign接口 開啟連接池&#xff0c;優化Feign性能 3.1 引入OkHttp 3.2 配置啟用OkHttp連接池 3.3 驗證連接池生效 Feign最佳…

VARIAN安捷倫真空泵維修清潔保養操作SOP換油操作流程內部轉子圖文并茂內部培訓手側

VARIAN安捷倫真空泵維修清潔保養操作SOP換油操作流程內部轉子圖文并茂內部培訓手側

【android bluetooth 案例分析 03】【PTS 測試 】【PBAP/PCE/SSM/BV-10-C】

1. PBAP/PCE/SSM/BV-10-C [PCE Does not share PbapSupportedFeatures bits] 這個 PTS 測試用例 PBAP/PCE/SSM/BV-10-C 的核心目的是驗證 PBAP 客戶端&#xff08;PCE&#xff09;在與舊版服務器通信時&#xff0c;不會發送 PbapSupportedFeatures 特性位&#xff0c;以確保兼…

批量刪除OpenStack實例

在Linux終端實現批量刪除OpenStack實例&#xff0c;支持并發刪除、安全確認、重試機制、優先清理運行中實例 #!/bin/bash # # 增強版 OpenStack 刪除實例腳本 # 功能&#xff1a;支持并發刪除、安全確認、重試機制、優先清理運行中實例 # 更新&#xff1a;2025年4月30日 # ##…

# 基于 Python 和 jieba 的中文文本自動摘要工具

基于 Python 和 jieba 的中文文本自動摘要工具 在信息爆炸的時代&#xff0c;快速準確地提取文本核心內容變得至關重要。今天&#xff0c;我將介紹一個基于 Python 和 jieba 的中文文本自動摘要工具&#xff0c;幫助你高效地從長文本中提取關鍵信息。 一、背景與需求 在處理…

Seaborn數據可視化庫

一、Seaborn介紹&#xff1a;基于Matplotlib的Python數據可視化庫&#xff0c;專注繪制統計圖形&#xff0c;簡化可視化過程&#xff0c;提供高級接口和美觀默認主題。 二、安裝與導入 1.安裝&#xff1a;可使用pip install seaborn或conda install seaborn&#xff0c;也可使…

機器視覺2D碼垛和機器視覺3D碼垛的區別

機器視覺3D碼垛是一種結合3D視覺技術和工業機器人的自動化系統,主要用于在復雜環境中精準識別、定位并堆疊(碼垛)各種形狀、尺寸的物體。它通過3D傳感器(如激光雷達、結構光相機、雙目視覺等)獲取物體的三維空間信息,并結合算法規劃機器人的抓取路徑和碼放策略,實現高效…

Python魔法函數深度解析

一、魔法函數是什么&#xff1f; 魔法函數&#xff08;Magic Methods&#xff09;是Python中以雙下劃線&#xff08;__xx__&#xff09;包裹的特殊方法&#xff0c;它們為類提供了一種與Python內置語法深度集成的能力。這些方法由解釋器自動調用&#xff0c;無需顯式調用&…

C++負載均衡遠程調用學習之自定義內存池管理

目錄 1.內存管理_io_buf的結構分析 2.Lars_內存管理_io_buf內存塊的實現 3.buf總結 4.buf_pool連接池的單例模式設計和基本屬性 5.buf_pool的初始化構造內存池 6.buf_pool的申請內存和重置內存實現 7.課前回顧 1.內存管理_io_buf的結構分析 ## 3) Lars系統總體架構 ? …

流水線問題(算法設計)C++

目錄 一、需求分析 1.1 問題描述 1.2 數據需求 1.3 功能需求 1.4 開發環境 二、概要設計 2.1 抽象數據類型 ADT 的定義 2.2 系統的主要功能模塊 2.3 功能模塊聯系圖 三、詳細設計 3.1 數據結構設計 3.2 主要算法 四、系統運行及結果分析 1. 用戶界面 2. 程序運行…