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

1. 基本概念

1.1 什么是模板?

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

1.2 模板有什么用?

模板可以使函數(shù)或者類只寫一份代碼而對應(yīng)不同的類型。

1.3 模板編程/泛型編程

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

1.4 模板分類

模板分為函數(shù)模板與類模板兩類。

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

2. 函數(shù)模板

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

例如:

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

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

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

3. 類模板

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

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

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

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

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

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

類模板參數(shù)允許自動類型轉(zhuǎn)換(隱式轉(zhuǎn)換);函數(shù)模板參數(shù)不允許自動類型轉(zhuǎn)換(隱式轉(zhuǎn)換)
在模板參數(shù)列表中,classtypename完全一樣。但是在語義上,class表示類,typename代表所有類型(類以及基本類型)。
請盡量使用typename

函數(shù)模板實(shí)參類型不一致問題

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

模板實(shí)例化時,

Max(2,2.4)

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

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

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

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í)參類型
Max<int>(2,2.4)

或者

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

或者

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

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

函數(shù)模板實(shí)例顯示指定模板實(shí)參可以顯示指定模板實(shí)參,也可以不指定(類型自動推導(dǎo)),類模板實(shí)例化必須

5. 特化

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

模板特化分類

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

5.1 函數(shù)模板特化

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

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

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

5.2 類模板特化

特點(diǎn):類模板特化,每個成員函數(shù)必須重新定義。

類模板特化分為兩種

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

5.2.1 全特化

步驟:

  1. 聲明一個模板空參數(shù)列表template<>
  2. 在類名稱后面的<>中顯示指定類型。

示例:

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

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

5.2.2 偏特化

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

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

步驟:

  1. 在一個模板類參數(shù)列表不指定或者指定部分具體類型。
  2. 在類名稱后面的對應(yīng)類型中顯示指定該類型。

示例:

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

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

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

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

模板原理

模板通常會被編譯兩次

  1. 實(shí)例化前,檢查模板代碼是否有語法錯誤。
  2. 實(shí)例化中,檢查模板代碼調(diào)用是否合法。

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


非類型模版參數(shù)

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

技巧

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

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

類模板

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

類實(shí)例化成對象,類模板實(shí)例化成類。

  • 類模板:不完整的類,一個或者多個成員類型未確定。
  • 函數(shù)模板:不完整的函數(shù),一個或者多個參數(shù)類型未確定。

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

實(shí)例

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

// 引用類型模板
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;
}

// -------------------------------------------------
// 指針類型模板(函數(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)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容