最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解C++中函數(shù)模板的定義與使用

 更新時(shí)間:2022年09月06日 14:19:40   作者:一枚大果殼  
函數(shù)模板實(shí)質(zhì)就是參數(shù)化數(shù)據(jù)類型,稱這種編程模式為數(shù)據(jù)類型泛化編程。本文將通過示例來和大家一起了解下C++中函數(shù)模板的定義與使用,需要的可以參考一下

1. 前言

什么是函數(shù)模板?

理解什么是函數(shù)模板,須先搞清楚為什么需要函數(shù)模板。

如果現(xiàn)在有一個(gè)需求,要求編寫一個(gè)求 2 個(gè)數(shù)字中最小數(shù)字的函數(shù),這 2 個(gè)數(shù)字可以是 int類型,可以是 float 類型,可以是所有可以進(jìn)行比較的數(shù)據(jù)類型……

常規(guī)編寫方案:針對(duì)不同的數(shù)據(jù)類型編寫不同的函數(shù)。

#include <iostream>
using namespace std;
//針對(duì) int 類型 
int getMin(int num1,int num2) {
   return num1>num2?num2:num1; 
} 
//針對(duì)  float 類型
float getMin(float num1,float num2) {
   return num1>num2?num2:num1; 
}
//針對(duì) double 類型 
double getMin(double num1,double num2) {
   return num1>num2?num2:num1; 
}  

int main() {
    //整型數(shù)據(jù)比較
    int min=getMin(10,4);
    cout<<min<<endl;
    //float 類型數(shù)據(jù)比較
    float minf=getMin(3.8f,2.9f);
	cout<<minf<<endl; 
    //double 類型數(shù)據(jù)比較
	double mind=getMin(1.8,2.1);
	cout<<mind<<endl; 
	return 0;
}

重載函數(shù)(當(dāng)然上述幾個(gè)函數(shù)名也可以不相同)可以解決這個(gè)問題。顯然,上述 3 個(gè)函數(shù)的算法邏輯是一模一樣的,僅是函數(shù)的參數(shù)類型不一樣。既然函數(shù)的形式參數(shù)可以接受值不同的同類型數(shù)據(jù),能否把函數(shù)形參的數(shù)據(jù)類型也參數(shù)化,用來接受不同的數(shù)據(jù)類型。

函數(shù)模板實(shí)質(zhì)就是參數(shù)化數(shù)據(jù)類型,稱這種編程模式為數(shù)據(jù)類型泛化編程。

Tips: 泛化的意思是一般化、抽象化,先不明確指定,需要時(shí)再指定。

如:我對(duì)班長說,我需要一名學(xué)生幫我搬課桌。這名學(xué)生到底是誰,我沒有明確,由班長具體化。換在函數(shù)模板中,表示函數(shù)模板需要一種數(shù)據(jù)類型的數(shù)據(jù),具體是什么數(shù)據(jù)類型,由使用者決定。

2. 初識(shí)函數(shù)模板

2.1 語法

在重構(gòu)上述代碼時(shí),先了解一下函數(shù)模板的語法結(jié)構(gòu):

template <模板形式參數(shù)列表>  返回類型 函數(shù)名(函數(shù)形式參數(shù)列表)
{
函數(shù)體
}

語法結(jié)構(gòu)說明:

1.template關(guān)鍵字說明了此函數(shù)是一個(gè)函數(shù)模板。

2.template <>的尖括號(hào)里是模板參數(shù)列表,也可稱此處的參數(shù)為數(shù)據(jù)類型參數(shù),用來對(duì)函數(shù)算法所針對(duì)的數(shù)據(jù)類型的泛化,表示可以接受不同的數(shù)據(jù)類型。

Tips:模板參數(shù)列表中的參數(shù)可以是一個(gè)或多個(gè)泛化數(shù)據(jù)類型參數(shù),也可以是一個(gè)或多個(gè)具體數(shù)據(jù)類型參數(shù)。

泛化類型參數(shù)前面要加上 typename 關(guān)鍵字。

3.后面便是函數(shù)的一般性說明,只是在函數(shù)中可以使用模板數(shù)據(jù)類型參數(shù)。

Tips: 函數(shù)模板中有 2 類參數(shù),模板參數(shù)和函數(shù)參數(shù)。

使用函數(shù)模板重構(gòu)上面求最小值的代碼:

template<typename T> T getMin(T num1,T num2){
	return num1>num2?num2:num1; 
} 

說明:

1.typename T聲明了一個(gè)數(shù)據(jù)類型參數(shù),用于泛化任一種數(shù)據(jù)類型,或者說 T可以表示任意一種數(shù)據(jù)類型。

Tips:typename 是 C++11 標(biāo)準(zhǔn),也可以使用 class關(guān)鍵字,但建議不用,避免和類定義混淆。

2.T數(shù)據(jù)類型可以作為函數(shù)的參數(shù)類型、返回值類型、以及作為算法實(shí)施過程中臨時(shí)變量的數(shù)據(jù)類型。

Tips: T是一個(gè)變量標(biāo)識(shí)符,在遵循變量命名規(guī)則的前提下,可以起任意名稱。

2.2 實(shí)例化

函數(shù)模板如現(xiàn)實(shí)生活中制作陶瓷的模具一樣,只有往模具中注入原材料,才能生成可實(shí)用的陶瓷。函數(shù)模板不是函數(shù),僅是一個(gè)模板,不能直接調(diào)用,需要實(shí)例化后才能調(diào)用。

實(shí)例化:指編譯器根據(jù)開發(fā)者對(duì)函數(shù)模板注入的具體(實(shí)參)數(shù)據(jù)類型構(gòu)造出一個(gè)真正的函數(shù)實(shí)體(實(shí)例),這個(gè)過程由編譯器自動(dòng)完成,且實(shí)例化的函數(shù)對(duì)于開發(fā)者不可見。

int res= getMin<int>(1,6);
cout<<res<<endl;
//輸出結(jié)果:1

如上,編譯器通過函數(shù)模板<>內(nèi)的int數(shù)據(jù)類型,實(shí)例化的函數(shù)可以對(duì) int類型的數(shù)據(jù)進(jìn)行算法操作。同理,下面的代碼會(huì)讓編譯器實(shí)例化針對(duì)不同數(shù)據(jù)類型的數(shù)據(jù)進(jìn)行算法操作的函數(shù)。

//實(shí)例化原型為 float  getMin(float num1,float num2){函數(shù)體} 的函數(shù)
float resf=getMin<float>(3.2f,8.2f);
cout<<resf<<endl;
//實(shí)例化原型為 double  getMin(double num1,double num2){函數(shù)體} 的函數(shù)
double resd=getMin<double>(1.2,0.2);
cout<<resd<<endl;
//實(shí)例化原型為 char  getMin(char num1,char num2){函數(shù)體} 的函數(shù)
char resc=getMin<char>('A','B');
cout<<resc<<endl;
//輸出結(jié)果分別為  3.2f  0.2  A 

使用函數(shù)模板的優(yōu)點(diǎn)不言而喻,聲明一次,便可以實(shí)現(xiàn)針對(duì)不同數(shù)據(jù)類型的數(shù)據(jù)的操作。當(dāng)然,中間會(huì)有匹配、實(shí)例化的代價(jià)。

Tips:高級(jí)業(yè)務(wù)層面的一勞永逸往往會(huì)以犧牲底層的性能為代價(jià),但是,這是值得的。

除了通過顯示聲明數(shù)據(jù)類型提示編譯器實(shí)例化,也可以使用函數(shù)指針實(shí)例化。

typedef int(*PF)(int,int); // 1 
PF pf=getMin;  // 2
int res= pf(6,8);  //3
cout<<res;  //4

說明:

處先定義一個(gè)函數(shù)指針類型。

處這行代碼,千萬不要理解是取函數(shù)模板的地址,編譯器在底層做了相應(yīng)處理。

編譯器會(huì)根據(jù)函數(shù)指針類型說明先實(shí)例化一個(gè)函數(shù)。

再取實(shí)例化函數(shù)的內(nèi)存地址,并賦值給 pf。

3 處以函數(shù)指針方式調(diào)用函數(shù)。

實(shí)例化時(shí)要注意的幾個(gè)問題:

1.實(shí)例化時(shí),可能會(huì)有一個(gè)直觀問題:真的能指定任意一種數(shù)據(jù)類型實(shí)例化函數(shù)模板嗎?

答案是:任何高級(jí)層面的邏輯行為都不能脫離基礎(chǔ)知識(shí)的認(rèn)知范疇,不同的數(shù)據(jù)類型有著語法系統(tǒng)賦予它的運(yùn)算操作能力,當(dāng)指定一個(gè)不支持函數(shù)模板內(nèi)部算法操作的數(shù)據(jù)類型時(shí),必然會(huì)出錯(cuò)。

如聲明一個(gè)求 2 個(gè)數(shù)字相除的余數(shù)的函數(shù)模板。

template<typename T> T getYuShu(T num1,T num2) {
	return num1 % num2;
}

如果指定 double 數(shù)據(jù)類型實(shí)例化 getYuShu 函數(shù)模板時(shí),就會(huì)拋出錯(cuò)誤,因?yàn)?nbsp;double數(shù)據(jù)類型不能使用 %運(yùn)算符。

double res=getYuShu<double>(6.2,2.4);  //出錯(cuò)

Tips: 編譯器在實(shí)例化函數(shù)模板時(shí),會(huì)遵循語法標(biāo)準(zhǔn)檢查給定的數(shù)據(jù)類型是否支持函數(shù)模板中的運(yùn)算操作。

2.編譯器實(shí)例化的時(shí)機(jī)。

常規(guī)而言,編譯器會(huì)在程序中第一次需要函數(shù)模板的某個(gè)實(shí)例時(shí)對(duì)其進(jìn)行編譯。但是,同一份代碼中,可能會(huì)出現(xiàn)對(duì)同一個(gè)實(shí)例多次調(diào)用的需要,如下面的代碼:

template <typename T > test(T num) {
	return num;
}
int f() {
	int res= test<int>(12);
	return res;
}
double f1() {
	int res= test<int>(24);
	return double(res);
}

ff1函數(shù)都需要使用 test<int>實(shí)例,于編譯器而,無法知道 ff1函數(shù)誰先會(huì)被調(diào)用(也就無法確定第一次編譯的時(shí)間點(diǎn)),但為了保證編譯期間完成實(shí)例化工作,早期C++編譯器采用對(duì)同一實(shí)例每一次出現(xiàn)的地方都編譯的策略,然后從多個(gè)編譯結(jié)果中選一個(gè)作為最終結(jié)果,顯然,編譯時(shí)間會(huì)大大延長。

C++充許顯式實(shí)例化聲明,用來顯示指定某一個(gè)函數(shù)模板的實(shí)例化的時(shí)間點(diǎn),從而解決同一個(gè)實(shí)例被多次編譯的問題。其語法如下:

template 返回值類型 模板名<模板參數(shù)列表>(函數(shù)形參列表);

針對(duì)上述函數(shù)模板可以編寫如下代碼,告之編譯器編譯時(shí)間點(diǎn)。

template <typename T > test(T num) {
	return num;
}
//顯示指定實(shí)例化
template int test<int>(int);

Tips: 顯示聲明只對(duì)一個(gè)源文件有效。

2.3 實(shí)參推導(dǎo)

所謂實(shí)參推導(dǎo),在使用函數(shù)模板時(shí)省略<>,不明確指定數(shù)據(jù)類型參數(shù),而是由編譯器根據(jù)函數(shù)的實(shí)參類型自動(dòng)推導(dǎo)出類型參數(shù)的真正類型。如下代碼:

int res=getMin(4,7);

實(shí)參是int 類型, 編譯器由此推導(dǎo)出 T 是 int類型,從而使用 int類型實(shí)例化函數(shù)模板,類似于下面的顯示聲明代碼:

int res=getMin<int>(4,7);

實(shí)參推導(dǎo)可以像調(diào)用普通函數(shù)一樣使用函數(shù)模板。但是實(shí)參推導(dǎo)是有前提條件的:函數(shù)參數(shù)使用了類型參數(shù)的才能通過函數(shù)實(shí)參類型推導(dǎo)。如下的函數(shù)模板。

template <typename T1,typename T2> T2 myMax(T1 num1,T1 num2) {
	//函數(shù)體
}

因?yàn)?nbsp;T2是作為函數(shù)模板的返回類型,是無法通過實(shí)參類型推導(dǎo)出來的。如下圖所示:

使用如上函數(shù)模板,需要顯示指定具體的數(shù)據(jù)類型。

double res= myMax<int,double>(6,8); //正確

是否可以讓函數(shù)模板的類型參數(shù)一部分顯示指定,一部分由實(shí)參推導(dǎo)?

答案是可以,但是,要求在聲明函數(shù)模板時(shí),把需要顯示指定的類型參數(shù)放在前面,可由實(shí)參推導(dǎo)的參數(shù)類型放在后面。把上面的函數(shù)模板的 T1、T2參數(shù)說明交換位置。

template <typename T2,typename T1> T2 myMax(T1 num1,T1 num2) {
	//函數(shù)體
}

實(shí)例化時(shí),只需要顯示指定 T2的類型,T1類型由編譯器根據(jù)實(shí)參推導(dǎo)。如下代碼可正確調(diào)用。

double res= myMax<double>(6,8); //正確

編譯器把 T2指定為 double類型,然后根據(jù)實(shí)參68推導(dǎo)出 T1是 int類型。

了解什么是實(shí)參推導(dǎo)后,使用時(shí),需要知道實(shí)參推導(dǎo)是不支持自動(dòng)類型轉(zhuǎn)換的。如下代碼是錯(cuò)誤的。

int res=getMin(4,7.5); //錯(cuò)誤

編譯器認(rèn)定實(shí)參 4int類型,實(shí)參7.5是 double類型,那么是到底是使用 int 類型還是使用 double類型實(shí)例化 getMin 函數(shù)模板,會(huì)讓編譯器不知所措、左右為難。

Tips: 即使支持自動(dòng)類型轉(zhuǎn)換,于編譯器而言也無法知道開發(fā)者是想使用 int 類型還是 double 類型。如此自動(dòng)類型轉(zhuǎn)換沒有存在的意義。

對(duì)于上述問題可以采用如下幾種方案解決:

1.通過強(qiáng)制類型操作把實(shí)參轉(zhuǎn)換成統(tǒng)一數(shù)據(jù)類型。

int res=getMin(4,int(7.5));
//或者
int res=getMin(double(4),7.5);

2.顯示指定實(shí)例化時(shí)的數(shù)據(jù)類型。

int res=getMin<int>(4,7.5);
//或者
int res=getMin<double>(4,7.5);

3.如果有必要傳遞 2 個(gè)不同類型的參數(shù),可需要修改函數(shù)模板,使其能接受 2 種類型參數(shù)。

template<typename T1,typename T2> T1 getMin(T1 num1,T2 num2){
	return num1>num2?num2:num1; 
} 

3. 重載函數(shù)模板

C++中普通函數(shù)和函數(shù)模板可以一起重載,面對(duì)多個(gè)重載函數(shù),編譯器需要提供相應(yīng)的匹配策略。如下代碼:

//普通函數(shù)
int getMax(int num1,int num2){
	return num1>num2?num1:num2; 
} 
//函數(shù)模板
template<typename T> T getMax(T num1,T num2) {
	return num1>num2?num1:num2;
}

如下調(diào)用時(shí),編譯器是選擇普通函數(shù)還是函數(shù)模板?

int res= getMax(6,8);

函數(shù)實(shí)參是 int類型,相比較函數(shù)模板,普通函數(shù)不需要實(shí)例化可直接使用,編譯器會(huì)優(yōu)先選擇普通函數(shù)。但是如下的調(diào)用,編譯器會(huì)選擇函數(shù)模板。

getMax(2.4,6.8); //調(diào)用 getMax<double>(實(shí)參推導(dǎo))
getMax('a','b'); //調(diào)用 getMax<char>(實(shí)參推導(dǎo))
getMax<>(7,3) //調(diào)用 getMax<int> (實(shí)參推導(dǎo))
getMax<double>(4,9) //顯示指定

編譯器選擇函數(shù)模板的原則:

如果函數(shù)模板能實(shí)例出一個(gè)完全與函數(shù)實(shí)參類型相匹配的函數(shù),那么就會(huì)選擇函數(shù)模板,如getMax(2.4,6.8); 調(diào)用。編譯器會(huì)根據(jù)函數(shù)模板實(shí)例化一個(gè)double getMax(double a,double b)函數(shù)與需求完全相匹配的函數(shù)。

如果即想使用實(shí)參推導(dǎo),且想使用函數(shù)模板而非普通函數(shù),可以使用空 <>尖括號(hào)語法。如上的 getMax<>(7,7);調(diào)用。一旦指定<>標(biāo)識(shí)符,顯示指定使用函數(shù)模板,無論其中是否有實(shí)參類型說明。

如下的函數(shù)調(diào)用,實(shí)參有 2 個(gè),但 2者之間可以發(fā)生自動(dòng)類型轉(zhuǎn)換。

charint之間可以相互轉(zhuǎn)換。

getMax('a',98);

編譯器會(huì)選擇誰?可以做一個(gè)實(shí)驗(yàn),把普通函數(shù)注釋,保留函數(shù)模板。

#include <iostream>
#include <cstring>
using namespace std;
//函數(shù)模板
template<typename T> T getMax(T num1,T num2) {
	return num1>num2?num1:num2;
}
int main(int argc, char** argv) {
    int t= getMax('a',98)
	return 0;
}

執(zhí)行后:

再恢復(fù)普通函數(shù)后執(zhí)行,代碼可以正常執(zhí)行。顯然,編譯器選擇的是普通函數(shù)。原因很簡(jiǎn)單,在使用實(shí)參推導(dǎo)時(shí),函數(shù)模板是不支持自動(dòng)類型轉(zhuǎn)換,而普通函數(shù)表示沒有壓力。

總結(jié)一下,選擇時(shí),編譯器會(huì)先考慮有沒有類型完全相匹配的普通函數(shù),沒有,試著看能不能實(shí)例化一個(gè)完全匹配的函數(shù)。

以上就是詳解C++中函數(shù)模板的定義與使用的詳細(xì)內(nèi)容,更多關(guān)于C++函數(shù)模板的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Qt自繪實(shí)現(xiàn)蘋果按鈕滑動(dòng)效果的示例代碼

    Qt自繪實(shí)現(xiàn)蘋果按鈕滑動(dòng)效果的示例代碼

    這篇文章主要介紹了Qt自繪實(shí)現(xiàn)蘋果按鈕滑動(dòng)效果的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 淺析C語言初階的常量和變量

    淺析C語言初階的常量和變量

    在C程序執(zhí)行過程中,其值不發(fā)生改變的量稱為常量,其值可變的量稱為變量,本文將帶你了解什么是常量和變量,以及使用方法,需要的朋友可以參考下
    2023-05-05
  • C語言實(shí)現(xiàn)帶頭結(jié)點(diǎn)的鏈表的創(chuàng)建、查找、插入、刪除操作

    C語言實(shí)現(xiàn)帶頭結(jié)點(diǎn)的鏈表的創(chuàng)建、查找、插入、刪除操作

    這篇文章主要介紹了C語言實(shí)現(xiàn)帶頭結(jié)點(diǎn)的鏈表的創(chuàng)建、查找、插入、刪除操作方法,對(duì)于了解數(shù)據(jù)結(jié)構(gòu)中鏈表的各項(xiàng)操作有很好的借鑒價(jià)值,需要的朋友可以參考下
    2014-09-09
  • C語言常用的編輯器你知道幾個(gè)

    C語言常用的編輯器你知道幾個(gè)

    這篇文章主要為大家詳細(xì)介紹了C語言常用的編輯器,中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • C語言 數(shù)據(jù)類型詳細(xì)介紹

    C語言 數(shù)據(jù)類型詳細(xì)介紹

    本文主要講解C語言 數(shù)據(jù)類型,這里整理了詳細(xì)的數(shù)據(jù)類型的資料,希望能幫助剛剛開始學(xué)習(xí)C語言的同學(xué)
    2016-08-08
  • C語言實(shí)現(xiàn)中國象棋

    C語言實(shí)現(xiàn)中國象棋

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)中國象棋,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • C/C++如何實(shí)現(xiàn)循環(huán)左移,循環(huán)右移

    C/C++如何實(shí)現(xiàn)循環(huán)左移,循環(huán)右移

    這篇文章主要介紹了C/C++如何實(shí)現(xiàn)循環(huán)左移,循環(huán)右移,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • C語言SetConsoleTextAttribute函數(shù)使用方法

    C語言SetConsoleTextAttribute函數(shù)使用方法

    這篇文章介紹了C語言SetConsoleTextAttribute函數(shù)的使用方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • C/C++實(shí)現(xiàn)線性單鏈表的示例代碼

    C/C++實(shí)現(xiàn)線性單鏈表的示例代碼

    使用鏈存儲(chǔ)結(jié)構(gòu)的線性存儲(chǔ)結(jié)構(gòu)為線性單鏈表,本文將分別利用C語言和C++實(shí)現(xiàn)線性單鏈表,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-05-05
  • C++?string如何獲取文件路徑文件名、文件路徑、文件后綴(兩種方式)

    C++?string如何獲取文件路徑文件名、文件路徑、文件后綴(兩種方式)

    這篇文章主要介紹了C++?string如何獲取文件路徑文件名、文件路徑、文件后綴(兩種方式),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
    2023-06-06

最新評(píng)論

通榆县| 永安市| 边坝县| 兴文县| 柳州市| 和龙市| 潢川县| 沁源县| 梅河口市| 闻喜县| 沂水县| 怀柔区| 东平县| 武穴市| 都匀市| 左云县| 尚义县| 左权县| 通州市| 文安县| 新晃| 瓮安县| 枣庄市| 高清| 德钦县| 南木林县| 罗甸县| 紫云| 新郑市| 新和县| 浮梁县| 昭通市| 汉沽区| 西青区| 尼玛县| 荆州市| 苍溪县| 林州市| 高台县| 故城县| 岐山县|