C++模板進階

目錄

非類型模板參數

類模板的特化

分類

函數模板的特化

模板分離編譯

問題

解決方法

1)不對模板定義進行分離或對模板進行特例化;

2)將聲明和定義放在同一個文件

總結


關于C++模板的使用在《C++類和對象》中有介紹,本篇博客主要幫助讀者對C++模板的一些特殊用法進行總結。

std::string的模擬實現-CSDN博客文章瀏覽閱讀881次,點贊40次,收藏38次。通過模擬實現string可以幫助讀者理解string成員函數的底層邏輯,讓讀者更準確地使用string中的成員函數。 https://blog.csdn.net/2401_87944878/article/details/145715615


非類型模板參數

模板參數分為兩種:類型模板參數和非類型模板參數。

類型模板參數:跟在class和typename后的類型。

非類型模板參數:用一個常量作為參數,即不再使用class或typename來定義的參數。

template<class T,size_t N=10>
class Seqlist
{
public:private:T _arr[N];size_t size;
};

如上圖所示:T是一個類型模板參數,用于替代各自類型;而N就是一個非類型模板參數,用于記錄說要開辟的靜態順序表的大小,默認為10。

簡而言之:就是有具體類型的參數就是非類型模板參數。

但是同樣非類型模板參數也有一些要求:

1)參數應被當作常量使用。

2)參數類型必須是整形(bool,int,char,enum),指針,引用。(C++20添加了部分其他類型);


類模板的特化

在一些情況下,我們又是要對類的部分類型進行特殊化處理,即T在不同類型下,可能會出現不同的需求(函數實現),此時就需要引入類模板的特例化。

template<class T1,class T2>
class Date
{
public:
///
///   .....實現類成員函數
///
private:T1 _a;T2 _b;
};

上面代碼是非特化模板,T1和T2可以表示任意類型。在編譯階段才去實例化為具體類型。

template<>
class Date<int, int>
{
public:
/// 
///  ......實現類成員函數
/// 
private:int _a;int _b;
};

以上代碼是對Date類進行特例化,指明是<int ,int >類型。類模板特例化后相當于一個新的"類",但是這個類也不能脫離非特例化類獨自出現,因為相當于新"類",所以需要自己再手動實現其功能(函數)

那么對于特例化模板參數和非特例化模板參數來說,編譯器會對非特例化模板參數進行實例化來實現類???

實際上是不會的:如果會那我們對模板特例化就沒有了意義,同時編譯器已經識別了類型匹配,它會偷懶直接去掉現成的,而不是去耗時耗力的實例化。

Date<int, int> d1;   //去直接調用特例化的模板類
Date<char, int> d2;  //將模板參數實例化后調用

分類

類模板的特化分為兩種:全特化和偏特化。

都是字面意思:全特化就是全部模板參數都有指定;偏特化指的是部分模板參數被指定或者對某一類型進行限制。

//非特例化
template<class T1,class T2>
class test
{
public:private:T1 _a;T2 _b;
};

全特例化:不用給模板參數

//全特例化
template<>
class test<int, char>
{
public:private:int _a;char _b;
};

偏特例化:部分參數指定

//偏特例化
template<class T2>
class test<int,T2>
{
public:private:int _a;T2 _b;
};

偏特例化:對類型進行限制;

此處演示特例化為指針,也可以限制為引用...

//偏特例化:對類型進行限制
template<class T1, class T2>
class test<T1*,T2*>  //將其參數限制為指針
{
public:private:T1* _a;T2* _b;
};

當然也可以對類型進行混合限制。

//偏特例化:對類型進行限制
template<class T1, class T2>
class test<T1&, T2*>  //第一個參數限制為引用,第二個參數限制為指針
{
public:private:T1& _a;T2* _b;
};

?注意:以上代碼的成員函數均沒有寫出,但是要知道的是:特化的類成員,類函數需要自己寫來進行特殊化處理。


函數模板的特化

與類模板一樣,函數模板也能進行特例化。

下面實現一個比較的函數。

template<class T>
bool Less(T x, T y)
{return x < y;
}

以上是實現一個各種類型的交換函數。但是當實參是指針的時候,比較就會比較的是指針的地址,這不是我們想要的結果,所以進行特化。

template<>
bool Less<int*>(int* x, int* y)
{return *x < *y;
}
template<class T>
bool Less(T* x, T* y)
{return *x < *y;
}

模板分離編譯

問題

模板分離編譯是一個很不推薦的寫法,不提倡將函數的聲明和定義分離到兩個文件中去。

以下代碼實現一個仿函數來實現小于比較。

"test.h"頭文件

namespace less
{template<class T>class Less{public:bool operator()(T x,T y);};
}

test.cpp文件

template<class T>
bool less::Less<T>::operator()(T x, T y)
{return x < y;
}

main函數文件調用

using namespace less;
Less<int> less;
int a = 10;
int b = 33;
cout << less(a, b) << endl;

可以看到將類的函數的聲明和定義分離,但是調用后卻報錯了。

可以看到此處運行時不是編譯錯誤,而是連接錯誤,編譯器沒有找到指定的函數,為什么呢??

編譯器沒有找到函數意味著在test.cpp文件中函數的地址沒有進入函數表。

原因在于:在編譯期間,每個文件都是分開編譯的,main函數中只包含頭文件,檢查語法時編譯器在頭文件中找到了仿函數的聲明認為有這個函數,但是test.cpp文件中的仿函數是模板函數,相當于一個圖紙,沒有實例化所以不會在test,cpp函數表中生成函數地址,test.cpp文件函數表中也就沒有仿函數地址,鏈接時就會報錯了。

解決方法

1)不對模板定義進行分離或對模板進行特例化;

此處對上面代碼中的模板進行特例化。

頭文件顯示實例化

template<class T>
class Less
{
public:bool operator()(T x,T y);
};template<>
class Less<int>
{
public:bool operator()(int x, int y);
};

test.cpp文件

bool less::Less<int>::operator()(int x, int y)
{return x < y;
}

2)將聲明和定義放在同一個文件

在C++的庫中,常常使用"xxxx.hpp"或"xxxx.h"文件來存放類模板函數的聲明和定義。


?補充

typename和class的區別

typename和class都是模板類型的聲明,在大多數情況下其沒有本質區別,但是typename有指明類型的意思。以下是只能用typename的特例。

template<class T,class Container=deque<T>>
class Print
{
public:void test(){Container::const_iterator it = _con.begin();}private:Container _con;
};

以上代碼,類成員函數test中定義了一個it的迭代器,看上去沒有任何問題,但是編譯時卻報錯了。

可以看到此處出現了語法錯誤,編譯器無法確定Continer::const_iterator是什么。

為什么編譯器無法判斷其是什么呢???

原因:Container沒有實例化所以編譯器不知道這個容器里面定義了什么。那Container::a,其中a可以是什么???a可以是一個靜態變量,一個內部類,也能是一種類型等等,編譯器無法識別其具體是什么,所以此處需要指明其是類型,即添加typename的前綴。

typename Container::const_iterator it = _con.begin();

關于array

在C++中添加了一個數組的類array,實際上其與數組沒有很大的區別,唯一的區別可能就是array比arr對于越界的檢查更嚴格。


總結

模板既有優點也有缺點。

優點:1)模板服用代碼,節省資源,更快的迭代開發;

? ? ? ? ? ?2)增強了代碼的靈活性。

缺點:1)導致代碼膨脹問題,編譯時間增加;

? ? ? ? ? ?2)出錯時,報錯信息非常凌亂,不易定位錯誤位置。

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

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

相關文章

Ubuntu togo系統讀寫性能與原生系統測試

我前面把一個Ubuntu環境拷貝到了一個10Gbps的硬盤盒制作了一個Ubuntu togo的系統&#xff0c;帖子在這里&#xff0c;這篇文章主要用于測試使用Ubuntu togo的系統和原生系統的性能差異。 以下是測試Ubuntu togo系統與原系統性能差異的具體方案&#xff0c;結合移動硬盤特性及參…

【css酷炫效果】實現魚群游動動態效果

【css酷炫效果】實現小魚游動動態效果 緣創作背景css代碼創建div容器引入jquery引入魚群js完整代碼效果圖成品資源下載鏈接:點擊下載 緣 在開發系統功能的時候,無意間看到了小魚游動特效,感覺很有意思,就在網上找了相關教程,分享給大家。 創作背景 剛看到csdn出活動了…

停車場停車位數據集,標注停車位上是否有車,平均正確識別率99.5%,支持yolov5-11, coco json,darknet,xml格式標注

停車場停車位數據集&#xff0c;標注停車位上是否有車&#xff0c;平均正確識別率98.0&#xff05;&#xff0c;支持yolov5-11&#xff0c; coco json&#xff0c;darknet&#xff0c;xml格式標注 數據集-識別停車場所有車輛的數據集 數據集分割 一共184張圖片 訓練組 89&am…

結合基于標簽置信度的特征選擇方法用于部分多標簽學習-簡介版

假設 部分多標簽學習&#xff08;PML&#xff09;假設&#xff1a;假設樣本的標簽集合中存在偽正標簽&#xff0c;即某些標簽可能是錯誤的。目標是從候選標簽集中識別出真實標簽。特征與標簽的關系假設&#xff1a;假設不同的標簽對應的特征子空間可能是不同的&#xff0c;而不…

Lora微LLAMA模型實戰

引言 本文介紹如何復現Alpaca-lora&#xff0c;即基于alpaca數據集用lora方法微調Llama模型。 環境準備 實驗環境用的是lanyun&#xff0c;新用戶點擊注冊可以送算力。 下載huggingface上的模型是一個令人頭疼的問題&#xff0c;但在lanyun上可以通過在終端運行source /etc…

Maven常見問題匯總

Maven刷新,本地倉庫無法更新 現象 This failure was cached in the local repository and resolution is not reattempted until the update interval of aliyunmaven has elapsed or updates are forced原因 因為上一次嘗試下載&#xff0c;發現對應的倉庫沒有這個maven配置…

什么是站群服務器?站群服務器應該怎么選?

站群服務器是專門用于托管和管理多個網站的服務器。通常用于SEO優化、內容分發、廣告推廣等場景&#xff0c;用戶可以通過一個服務器管理多個站點&#xff0c;提升效率并降低成本。選擇站群服務器時&#xff0c;需根據業務需求、性能要求、IP資源等因素進行綜合考慮。 什么是站…

分享一個項目中遇到的一個算法題

需求背景&#xff1a; 需求是用戶要創建一個任務計劃在未來執行&#xff0c;要求在創建任務計劃的時候判斷選擇的時間是否符合要求&#xff0c;否則不允許創建&#xff0c;創建的任務類型有兩種&#xff0c;一種是單次&#xff0c;任務只執行一次&#xff1b;另一種是周期&…

【LInux進程六】命令行參數和環境變量

【LInux進程六】命令行參數和環境變量 1.main函數的兩個參數2.利用main函數實現一個簡單的計算器3.環境變量之一&#xff1a;PATH4.修改PATH5.在命令行解釋器bash中查看所有環境變量6.用自己寫的程序查看環境變量7.main函數的第三個參數8.本地的環境變量和環境變量9.環境變量具…

時間軸版本-2.0

文章簡述 這是本人自己封裝的時間軸2.0版本的代碼&#xff0c;用到了TypeScriptJavaScript 這篇文章只有代碼和具體的使用方式&#xff0c;如果想看具體的講解可以參考本人寫的時間軸1.0版本的&#xff0c;在1.0版本中可能計算時間線的邏輯略有不同&#xff0c;但是大致的計算…

大語言模型的壓縮技術

盡管人們對越來越大的語言模型一直很感興趣&#xff0c;但MistralAI 向我們表明&#xff0c;規模只是相對而言的&#xff0c;而對邊緣計算日益增長的興趣促使我們使用小型語言獲得不錯的結果。壓縮技術提供了一種替代方法。在本文中&#xff0c;我將解釋這些技術&#xff0c;并…

大華HTTP協議在智聯視頻超融合平臺中的接入方法

一. 大華HTTP協議介紹 大華HTTP協議是大華股份&#xff08;Dahua Technology&#xff09;為其安防監控設備開發的一套基于HTTP/HTTPS的通信協議&#xff0c;主要用于設備與客戶端&#xff08;如PC、手機、服務器&#xff09;之間的數據交互。該協議支持設備管理、視頻流獲取、…

Linux內核實時機制28 - RT調度器11 - RT 組調度

Linux內核實時機制28 - RT調度器11 - RT 組調度 相關數據結構 內核中通過static int sched_rt_runtime_exceeded(struct rt_rq *rt_rq)函數來判斷實時任務運行時間是否超出帶寬限制,判斷這個運行隊列rt_rq的運行時間是否超過了額定的運行時間。而“運行時間”和“額定時間”都…

java,poi,提取ppt文件中的文字內容

注意&#xff0c;不涉及圖片處理。 先上pom依賴&#xff1a; <!-- 處理PPTX文件 --><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version></dependency><!--…

7、vue3做了什么

大佬認為有何優點&#xff1a; 組合式api----邏輯集中、對ts有更好的支持RFC–開放了一個討論機制&#xff0c;可以看到每一個api的提案&#xff0c;方便源碼維護&#xff0c;功能擴展&#xff0c;大家一起討論 官方rfc響應式獨立&#xff0c;new Proxy&#xff0c;天生自帶來…

多人在線聊天系統,創建群,視頻,語音,自帶帶授權碼

多人在線聊天系統&#xff0c;創建群&#xff0c;視頻&#xff0c;語音 帶授權碼&#xff0c;授權碼限制 10 個網站&#xff0c;需要下載研究吧 在線聊天&#xff0c;創建群&#xff0c;表情&#xff0c;圖片&#xff0c;文件&#xff0c;視頻&#xff0c;語音&#xff0c;自…

數據結構概覽

關鍵點&#xff1a; 數據結構是組織和存儲數據的方式&#xff0c;幫助高效訪問和操作數據。常見類型包括數組、鏈表、棧、隊列、樹和圖&#xff0c;每種都有特定用途。代碼示例和實際應用場景將幫助初學者理解這些概念。 什么是數據結構&#xff1f; 數據結構就像你整理書架或…

Android studio點擊運行按鈕在build\intermediates\apk\debug目錄下生成的apk在真機上安裝失敗,提示test only

Android studio點擊運行按鈕在build\intermediates\apk\debug目錄下生成的apk在真機上安裝失敗&#xff0c;提示test only DeepSeek R1 思考 15 秒 思考過程 針對Android Studio生成的APK在真機安裝時提示“test only”的問題&#xff0c;以下是詳細解決方案&#xff1a; 1.…

NFC 碰一碰發視頻源碼搭建,支持OEM

一、引言 NFC&#xff08;Near Field Communication&#xff09;近場通信技術&#xff0c;以其便捷、快速的數據交互特性&#xff0c;正廣泛應用于各個領域。其中&#xff0c;NFC 碰一碰發視頻這一應用場景&#xff0c;為用戶帶來了新穎且高效的視頻分享體驗。想象一下&#x…

Python基礎語法全解析:從入門到實踐

Python作為一門簡潔高效、功能強大的編程語言&#xff0c;憑借其易讀性和豐富的生態系統&#xff0c;已成為編程領域的“明星語言”。本文將系統講解Python的核心語法&#xff0c;涵蓋變量、數據類型、控制結構、函數、模塊等核心概念&#xff0c;幫助讀者快速掌握編程基礎。 一…