C++基礎(chǔ)8:模板編程/泛型編程

1. 基本概念

1.1 什么是模板匾效?

模板(Template)是允許函數(shù)或者類(lèi)通過(guò)泛型(generic types)的形式表現(xiàn)或運(yùn)行的特性。

1.2 模板有什么用坎藐?

模板可以使函數(shù)或者類(lèi)只寫(xiě)一份代碼而對(duì)應(yīng)不同的類(lèi)型价说。

1.3 模板編程/泛型編程

一種獨(dú)立于特定類(lèi)型的編碼方式

1.4 模板分類(lèi)

模板分為函數(shù)模板與類(lèi)模板兩類(lèi)棵磷。

  • 函數(shù)模板(Function template):使用泛型參數(shù)的函數(shù)(function with generic parameters)
  • 類(lèi)模板(Class template):使用泛型參數(shù)的類(lèi)(class with generic parameters)

2. 函數(shù)模板

  • 模板聲明
template <模板形參表> 函數(shù)返回類(lèi)型 函數(shù)(形參表);
  • 模板定義
template <模板形參表>
函數(shù)返回類(lèi)型 函數(shù)(形參表){
      函數(shù)體;
};

例如:

template <typename T> T Max(T a,T b){
        return a>b?a:b;
}
  • 模板實(shí)例化
函數(shù)(實(shí)參表)

產(chǎn)生模板特定類(lèi)型的函數(shù)或者類(lèi)的過(guò)程稱(chēng)為實(shí)例化
調(diào)用函數(shù)模板與調(diào)用函數(shù)完全一致歹啼。

  • 實(shí)例
    最值函數(shù)Max(),Min()
    字符串轉(zhuǎn)數(shù)值Ston()

3. 類(lèi)模板

  • 模板聲明
template <模板形參表> class 類(lèi)名;
  • 模板定義
template <模板形參表>
class 類(lèi)名 {
}
  • 模板實(shí)例化
類(lèi)名<模板實(shí)參表> 對(duì)象;
  • 模板參數(shù)表
    多個(gè)模板參數(shù)之間,分割玄渗。模板參數(shù),模板參數(shù),...
  • 模板參數(shù)
  • 類(lèi)型形參
    class 類(lèi)型形參或者typename 類(lèi)型形參

類(lèi)模板的聲明與實(shí)現(xiàn)通常都寫(xiě)在頭文件中座菠,是不能夠分開(kāi)的。

  • 實(shí)例
    復(fù)數(shù)類(lèi)Complex
    三角形類(lèi)Triangle

4. 模板參數(shù)推導(dǎo)/推演(deduction)

模板參數(shù)推導(dǎo)/推演(deduction):由模板實(shí)參類(lèi)型確定模板形參的過(guò)程藤树。

實(shí)例化有兩類(lèi):
顯示實(shí)例化:代碼中明確指定類(lèi)型的實(shí)例化
隱式初始化:根據(jù)參數(shù)類(lèi)型自動(dòng)匹配的實(shí)例化

類(lèi)模板參數(shù)允許自動(dòng)類(lèi)型轉(zhuǎn)換(隱式轉(zhuǎn)換);函數(shù)模板參數(shù)不允許自動(dòng)類(lèi)型轉(zhuǎn)換(隱式轉(zhuǎn)換)
在模板參數(shù)列表中浴滴,classtypename完全一樣。但是在語(yǔ)義上也榄,class表示類(lèi)巡莹,typename代表所有類(lèi)型(類(lèi)以及基本類(lèi)型)司志。
請(qǐng)盡量使用typename

函數(shù)模板實(shí)參類(lèi)型不一致問(wèn)題

template <typename T> 
inline const T& Max(const T& a, const T& b){
        return a>b?a:b;
}

模板實(shí)例化時(shí)甜紫,

Max(2,2.4)

參數(shù)推導(dǎo)會(huì)出現(xiàn)模板實(shí)參類(lèi)型intdouble不一致的錯(cuò)誤。
解決方法:

  1. 每個(gè)模板參數(shù)獨(dú)立類(lèi)型
template <typename T , typename U> inline const T& Max(const T& a, const U& b){
        return a>b?a:b;
}

注意:這種解決方法還有一個(gè)問(wèn)題骂远,就是返回值只能強(qiáng)制設(shè)置為T或者U囚霸,不能自動(dòng)推導(dǎo)。C++11的后置推導(dǎo)解決這個(gè)問(wèn)題激才。

template <typename T, typename U> 
inline auto Max(const T& a, const U& b)->decltype(a>b?a:b)
{
        return a>b?a:b;
}
  1. 顯示指定模板實(shí)參類(lèi)型
Max<int>(2,2.4)

或者

Max<double>(2,2.4)
  1. 實(shí)參強(qiáng)制類(lèi)型轉(zhuǎn)換
Max(2,static_cast<int>(2.4))

或者

Max(static_cast<double>(2),2.4)

模板參數(shù)推導(dǎo)不允許類(lèi)型自動(dòng)轉(zhuǎn)換拓型,模板參數(shù)必須嚴(yán)格匹配。

函數(shù)模板實(shí)例顯示指定模板實(shí)參可以顯示指定模板實(shí)參瘸恼,也可以不指定(類(lèi)型自動(dòng)推導(dǎo))劣挫,類(lèi)模板實(shí)例化必須

5. 特化

  • 模板特化(specialization):模板參數(shù)在某種特定類(lèi)型下的具體實(shí)現(xiàn)稱(chēng)為模板的特化。模板特化有時(shí)也稱(chēng)之為模板的具體化东帅。
    特化作用
  1. 對(duì)于某種特殊類(lèi)型压固,可以做特殊處理或者優(yōu)化。
  2. 避免實(shí)例化類(lèi)的時(shí)候產(chǎn)生詭異行為靠闭。

模板特化分類(lèi)

  1. 函數(shù)模板特化(Function specializations):對(duì)函數(shù)模板的全部模板類(lèi)型指定具體類(lèi)型帐我。
  2. 類(lèi)模板特化(Class specializations):對(duì)類(lèi)模板的全部或者部分模板類(lèi)型指定具體類(lèi)型。

5.1 函數(shù)模板特化

特點(diǎn):函數(shù)模板愧膀,卻只有全特化拦键,不能偏特化。
步驟:與類(lèi)的全特化相同
示例:

template<typename T>
void Func(const T& n){}

// 特化
template<>
void Func(const int& n){}

5.2 類(lèi)模板特化

特點(diǎn):類(lèi)模板特化檩淋,每個(gè)成員函數(shù)必須重新定義芬为。

類(lèi)模板特化分為兩種

  • 全特化(Full specializations):具體指定模板的全部模板參數(shù)的類(lèi)型。
  • 局部特化(Partial specializations):具體指定模板的部分模板參數(shù)的類(lèi)型蟀悦。

5.2.1 全特化

步驟:

  1. 聲明一個(gè)模板空參數(shù)列表template<>
  2. 在類(lèi)名稱(chēng)后面的<>中顯示指定類(lèi)型媚朦。

示例:

// 模板  
template<class T>
class Test{};

// 全特化
template<>
class Test<int*>{};

5.2.2 偏特化

偏特化就是部分特化,分為兩種情況

  1. 個(gè)數(shù)特化:只為部分模板參數(shù)指定具體類(lèi)型(模板參數(shù)個(gè)數(shù)變少)
  2. 范圍特化:模板參數(shù)不變熬芜,限制模板參數(shù)的匹配類(lèi)型(指針莲镣、引用、const)

步驟:

  1. 在一個(gè)模板類(lèi)參數(shù)列表不指定或者指定部分具體類(lèi)型涎拉。
  2. 在類(lèi)名稱(chēng)后面的對(duì)應(yīng)類(lèi)型中顯示指定該類(lèi)型瑞侮。

示例:

template<typename T1,typename T2>
class Test{};
  1. 將模板參數(shù)偏特化為相同類(lèi)型
template<typename T>
class Test<T,T>{};
  1. 將一個(gè)模板參數(shù)特化成具體類(lèi)型
template<typename T>
class Test<T,int>{};
  1. 把兩個(gè)類(lèi)型偏特化成指針類(lèi)型
template<typename T1,typename T2>
class Test<T1*,T2*>{};

實(shí)例:三元組模版Triple

類(lèi)模板特化的圆,相當(dāng)于函數(shù)模板的重載

全特化和偏特化的編碼區(qū)別:
全特化的模板參數(shù)列表為空template<>,偏特化的模板參數(shù)列表不為空半火。

模板原理

模板通常會(huì)被編譯兩次

  1. 實(shí)例化前越妈,檢查模板代碼是否有語(yǔ)法錯(cuò)誤。
  2. 實(shí)例化中钮糖,檢查模板代碼調(diào)用是否合法梅掠。

如何查看模板實(shí)例化的結(jié)果?https://cppinsights.io/


非類(lèi)型模版參數(shù)

非類(lèi)型模板的實(shí)參只能是整型常量店归、枚舉值或者指向外部鏈接對(duì)象的指針阎抒。
不能使用浮點(diǎn)型、類(lèi)對(duì)象消痛、內(nèi)部鏈接對(duì)象的指針且叁。

技巧

函數(shù)模板參數(shù)盡量使用引用類(lèi)型const &
例如:

template <typename T> inline const T& Max(const T& a, const T& b){
        return a>b?a:b;
}

類(lèi)模板

成員函數(shù):只有調(diào)用時(shí)才會(huì)被實(shí)例化。
靜態(tài)成員:每次類(lèi)模板實(shí)例化秩伞,都會(huì)被實(shí)例化逞带。

類(lèi)實(shí)例化成對(duì)象,類(lèi)模板實(shí)例化成類(lèi)纱新。

  • 類(lèi)模板:不完整的類(lèi)展氓,一個(gè)或者多個(gè)成員類(lèi)型未確定。
  • 函數(shù)模板:不完整的函數(shù)脸爱,一個(gè)或者多個(gè)參數(shù)類(lèi)型未確定遇汞。

如何查看模板實(shí)例化的結(jié)果?https://cppinsights.io/

實(shí)例

  1. 函數(shù)模板重載和特化
#include <iostream>
#include <cstring>
using namespace std;

// 引用類(lèi)型模板
template <typename T>
bool Equal(const T& a,const T& b){
    return a == b;
}

// 特化成浮點(diǎn)型
template<>
bool Equal(const double& a,const double& b){
    return abs(a-b) < 1e-6;
}

// -------------------------------------------------
// 指針類(lèi)型模板(函數(shù)模板重載)
template<typename T>
bool Equal(const T* a,const T* b){
    return *a==*b;
}

// 特化成char*
template<>
bool Equal(const char* a,const char* b){
    return strcmp(a,b)==0;
}

int main(){
    cout << Equal(1,1) << endl;
    cout << Equal(1.2,1.2) << endl;
    cout << Equal(string("abc"),string("abc")) << endl;


    cout << Equal(1,2) << endl;
    cout << Equal(1.2,1.21) << endl;
    cout << Equal(string("abcd"),string("abc")) << endl;
    
    cout << Equal(1.2,(10.2-9)) << endl;


    int arr[] = {1,2,3,1};
    cout << Equal(arr,arr+3) << endl; // bool Equal(int*,int*)

    cout << Equal("abc","abcd") << endl;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末阅羹,一起剝皮案震驚了整個(gè)濱河市勺疼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌捏鱼,老刑警劉巖执庐,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異导梆,居然都是意外死亡轨淌,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)看尼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)递鹉,“玉大人,你說(shuō)我怎么就攤上這事藏斩□锝幔” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵狰域,是天一觀的道長(zhǎng)媳拴。 經(jīng)常有香客問(wèn)我黄橘,道長(zhǎng),這世上最難降的妖魔是什么屈溉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任塞关,我火速辦了婚禮,結(jié)果婚禮上子巾,老公的妹妹穿的比我還像新娘帆赢。我一直安慰自己,他們只是感情好线梗,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布椰于。 她就那樣靜靜地躺著,像睡著了一般缠导。 火紅的嫁衣襯著肌膚如雪廉羔。 梳的紋絲不亂的頭發(fā)上溉痢,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天僻造,我揣著相機(jī)與錄音,去河邊找鬼孩饼。 笑死髓削,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的镀娶。 我是一名探鬼主播立膛,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼梯码!你這毒婦竟也來(lái)了宝泵?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤轩娶,失蹤者是張志新(化名)和其女友劉穎儿奶,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鳄抒,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡闯捎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了许溅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓤鼻。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖贤重,靈堂內(nèi)的尸體忽然破棺而出茬祷,到底是詐尸還是另有隱情,我是刑警寧澤并蝗,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布祭犯,位于F島的核電站耐朴,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏盹憎。R本人自食惡果不足惜筛峭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望陪每。 院中可真熱鬧影晓,春花似錦、人聲如沸檩禾。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)盼产。三九已至饵婆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間戏售,已是汗流浹背侨核。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留灌灾,地道東北人搓译。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像锋喜,于是被迫代替她去往敵國(guó)和親些己。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • C++ 模板簡(jiǎn)介 一嘿般、模板 使用模板的目的就是能夠讓程序員編寫(xiě)與類(lèi)型無(wú)關(guān)的代碼段标。 模板是一種對(duì)類(lèi)型進(jìn)行參數(shù)化的工具...
    MinoyJet閱讀 2,379評(píng)論 0 12
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,523評(píng)論 1 51
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)炉奴,斷路器逼庞,智...
    卡卡羅2017閱讀 134,701評(píng)論 18 139
  • 秋雨滴落輕打梧桐, 翩翩葉落隨風(fēng)盆佣。 寂寞相思往堡, 心涼誰(shuí)懂, 究竟耐何癡情共耍? 可曾相離虑灰, 可曾相守, 時(shí)時(shí)望秋水痹兜, ...
    六六幺幺九閱讀 453評(píng)論 0 2
  • #git初始化 初始化一個(gè)git倉(cāng)庫(kù)穆咐,使用‘git init’ 命令。 #設(shè)置名字和Email地址 ‘git...
    心羽暖姐姐閱讀 316評(píng)論 0 1