首頁 > 軟體

C++ 深入淺出探索模板

2022-04-15 13:00:10

非型別模板引數

模板引數分類型別形參與非型別形參。

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

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

注意:

  • 浮點數,類物件以及字串是不允許作為非型別模板的。
  • 非型別的模板引數必須在編譯期就能確認結果。

模板特化

有時候,編譯預設函數模板或者類別範本不能正確處理需要邏輯,需要針對一些情況特殊化處理,就要做模板特化。

通常情況下,使用模板可以實現一些與型別無關的程式碼,但對於一些特殊型別的可能會得到一些錯誤的結果,例如:

template<class T>
bool IsEqual(const T&left,const T&right)
{
    return left==right;
}
//針對字串型別要特殊化處理--寫一份函數模板的特殊化出來
template<>
bool IsEqual<char*>(const char* &left,const char* &right)
{
    return strcmp(left,right)==0;
}
​
int main()
{
    cout<<IsEqual(1,2)<<endl;//0
    cout<<IsEqual(1.1,1.1)<<endl;//1
    
    char p1[]="hello";
    char p2[]="hello";
    cout<<IsEqual(p1,p2)<<endl;//0
    
    const char* p3="hello";
    const char* p4="hello";
    cout<<IsEqual(p3,p4)<<endl;//1
}

此時,就需要對模板進行特化。即:在原模板類的基礎上,針對特殊型別所進行特殊化的實現方式。模板特化中分為函數模板特化與類別範本特化。

特化的本質:顯示指定範例化的模板

函數模板特化

函數模板特化步驟

  • 必須要先有一個基礎的函數模板
  • 關鍵字template後面接一對空的尖括號<>
  • 函數名後跟一對尖括號,尖括號中指定需要特化的型別
  • 函數形參表: 必須要和模板函數的基礎引數型別完全相同,如果不同編譯器可能會報一些奇怪的錯誤
template<>
bool IsEqual<const char* const>(const char* const &left,const char* &right)
{
    if(strcmp(left,right)>0)
        return true;
    return false;
}

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

類別範本特化

全特化

全特化既是將模板參數列中所有的引數都確定化

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

偏特化

針對任何模板引數進一步進行條件限制設計的特化版本,比如對於一下模板類:

template<class T1,class T2>
class Data
{
public:
    Data(){cout<<"Data<T1,T2>"<<endl;}
private:
    T1 _d1;
    T2 _d2;
};
//偏特化有以下兩種表現方式:
//1、部分特化:將函數中的一部分引數特化。
​
template<class T1>
class Data<T1,int>
{
public:
    Data(){cout<<"Data<T1,int>"<<endl;}
private:
    T1 _d1;
    int _d2;
}
//2、引數進一步的限制:偏特化並不僅僅是指特化部分引數,而是針對模板引數更進一步的條件限制所設計出來的一個特化版本
//兩個引數偏特化為指標型別
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(){cout<<"Data<T1&,T2&>"<<endl;}
private:
    const T1& _d1;
    const T2& _d2;
};
​
void test2()
{
    Data<double,int>d1;   //呼叫特化的int版本
    Data<int,double>d2;   //呼叫基礎模板
    Data<int *,int*>d3;   //呼叫特化的指標版本
    Data<int&,int&>d4(1,2); //呼叫特化的參照版本
}

模板分離編譯

分離編譯就是指一個程式由若干個原始檔共同實現,而每個原始檔單獨編譯生成目標檔案,最後將目標檔案連線起來形成單一的可執行檔案的過程稱為分離編譯模式。

模板的分離編譯

// a.h
template<class T>
T Add(const T& left, const T& right);
// a.cpp
template<class T>
T Add(const T& left, const T& right)
{
    return left + right;
}
// main.cpp
#include"a.h"
int main()
{
    Add(1, 2);
    Add(1.0, 2.0);
    return 0;
}

分析:

解決方法

  • 將宣告和定義放到一個檔案中。推薦使用
  • 模板定義的位置顯示範例化。不實用

總結

優點

  • 模板複用了程式碼,節省資源,更快的迭代開發,C++的標準模板庫(STL)因此而生
  • 增強了程式碼的靈活性

缺點

  • 模板會導致程式碼膨脹問題,也會導致編譯時間變長。
  • 出現模板編譯錯誤時,錯誤資訊非常雜亂,不易定位錯誤。

到此這篇關於C++ 深入淺出探索模板的文章就介紹到這了,更多相關C++ 模板內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com