1. 程式人生 > 其它 >C++:18---函式模板(template)

C++:18---函式模板(template)

技術標籤:指標pythonc++java

一、模板的定義

  • template<typename T>

  • 以關鍵字template開頭,後面跟一個模板引數列表,列表裡面用逗號將多個模板引數隔開定義的注意事項

模板的編譯

  • 當編譯器遇到一個模板定義時,並不生成程式碼。只有當例項化處模板的一個特定版本時,編譯器才會生成程式碼

  • 重點:通常,當我們呼叫一個函式/定義例項化一個類時,編譯器只需掌握函式的宣告/類的宣告即可,因此可以把函式/類的宣告放置在標頭檔案,而把函式/類的定義放置在原始檔中。但是模板則不同:為了例項化模板函式,編譯器必須掌握函式模板/類模板成員函式的宣告和定義,因此只能將模板函式/類的宣告和定義都放置在頭一個頭檔案/原始檔中(重點)

二、函式模板與模板函式

  • 函式模板:一個模板(是模板)

  • 模板函式:呼叫函式模板時生成的函式(是函式),也稱為函式模板的例項化

一個模板引數列表只和一個函式模板相對應。因此每定義一個函式模板就需要重新定義一個模板引數列表

//定義模板以及一個函式模板
template<typenameT>intcompare(constT&v1,constT&v2);int main(){compare(1,2);//模板函式,也稱為模板的例項化compare("ABC","DEF");//模板函式return0;}

三、模板型別引數

  • 模板引數列表不能為空

  • 模板引數既可以用typename宣告,也可以使用class宣告。不過建議前者

//定義模板以及一個函式模板
template<typenameT,classU>intcompare(constT&v1,constU&v2);int main(){compare(1,1);//T為int,U也為intcompare(1,"DEF");//T為int,U也為stringreturn 0;
}

四、非型別模板引數

  • 除了定義上面的模板型別引數,我們也可以定義非型別引數。

  • 一個非型別引數表示一個值而非一個型別。並且通過特定的型別名定義而非typename或class來定義

  • 當一個模板被例項化時,非型別引數被使用者提供或者編譯器推斷的值所代替。

  • 重點:一個非型別引數可以是一個整型、一個指向物件或函式的指標(或引用)。且實參必須是一個常量表達式

//定義模板以及一個函式模板。
template <unsigned N, unsigned M>
int compare(const char(&p1)[N], const char(&p2)[M])//傳入陣列的引用來比較陣列大小
{
return strcmp(p1, p2);
}
int main()
{
compare("hi","mom");//編譯器會使用字面值常量的大小來代替N和M
return 0;
}

五、inline、constexpr函式模板

  • 函式模板可以宣告為inline或constexpr。但是這些關鍵字必須放在函式的返回值型別前面,模板引數列表的後面

template<typename T>  //正確
inline T func(T const&);
constexpr template<typename T> //錯誤,constexpr位置錯誤
T func2(T const&);

六、定義型別無關的程式碼

  • 當我們定義函式模板時,如果函式能處理的功能只限於一些特定的情況,而不能作用於大多數的情況,那麼這個函式模板的操作性與可移植性就比較差

  • 為了解決上面這個問題,我們在定義函式模板時,就需要考慮型別無關與可移植性

案例:

  • 下面這個函式模板如果呼叫它比較兩個指標,而這兩個指標未指向相同的陣列,則程式碼的行為是未定義的

template <typename T>
int compare(const T& s1, const T& s2)
{
if (v1 < v2)
return -1;
if (v1 > v2)
return 1;
return 0;
}
  • 下面我們編寫了這個函式模板,也可以用於傳入指標也可以正常使用的函式模板(但是還不是最完美的,所以在定義時,要考慮各種因素而達到更高的標準)

template <typename T>
int compare(const T& s1, const T& s2)
{
if (less<T>()(v1,v2))
return -1;
if (less<T>()(v2, v1))
return 1;
return 0;
}

前方高能,我來出一個程式碼例子,來看看結果和你想的是否一致?

練習:



#include <iostream>
#include <cstring>
using namespace std;
template<typename T1,typename T2>
bool Compare(const T1& t1,const T2& t2)
{
        cout << "call Compare(const T1& t1,const T2& t2)" << endl;
        if(t1 > t2){
                return true;
        }
        return false;
}
bool Compare(const char* s1,const char* s2)
{
        cout << "call Compare(const char* s1,const char* s2)" << endl;
        return strcmp(s1,s2);
}
bool Compare(const float& t1,const float& t2)
{
                cout << "call Compare(const float& t1,const float& t2)" << endl;
                        if(t1 > t2){
                                                return true;
                                                        }
                                return false;
}
int main(){
        int a = 12,b=23;
        Compare(a,b);
        const char *p = "11111";
        const char *q = "00";
        Compare(p,q);


        float c=12.0,d=15.7;
        Compare(c,d);
                        return 0;
}


為什麼結果是

call Compare(const T1& t1,const T2& t2)

call Compare(const char* s1,const char* s2)

call Compare(const float& t1,const float& t2)

呢?接下來就是我們下一節要講的模板的特化。