模板小結

模板分爲 函數模板 和 類模版

泛型編程:編寫與類型無關的邏輯代碼,是代碼複用的一種手段。模板是泛型編程的基礎。

函數模板

函數模板:代表了一個函數家族,該函數與類型無關,在使用時被參數化,根據實參類型產生函數的
特定類型版本。


模板函數的格式

template<typename Param1, typename Param2,...,class Paramn> 
返回值類型 函數名(參數列表)
{
...
}

// typename和class都可以 但struct不行

模板函數也可以定義爲inline函數,inline關鍵字必須放在模板形參表之後,返回值之前,不能放在template之前


模板是一個藍圖,它本身不是類或者函數,編譯器用模板產生指定的類或者函數的特定類型版本,產
生模板特定類型的過程稱爲函數模板實例化。

#include <iostream>
using namespace std;
template <typename T, class T1>  // 模板形參名可以任意給  
inline T Add(T left, T1 right)
{
    return left + right;
}
int main()
{
    cout <<Add('1', 1) << endl;     //相當調用 char Add(char left, int right)
    cout << Add<int, char>('1', 1) << endl;  //相當調用 int Add(int left, char 1)  
    system("pause");
    return 0;
}

注意:在函數模板的內部不能指定缺省的模板實參。模板形參的名字在同一模板形參列表中只能使用一次.
模板被編譯了兩次:
實例化之前,檢查模板代碼本身,查看是否出現語法錯誤,如:遺漏分號
在實例化期間,檢查模板代碼,查看是否所有的調用都有效,如:實例化類型不支持某些函數調

一般不會轉換實參以匹配已有的實例化,相反會產生新的實例。
編譯器只會執行兩種轉換:
1、const轉換:接收const引用或者const指針的函數可以分別用非const對象的引用或者指針來調用
2、數組或函數到指針的轉換:如果模板形參不是引用類型,則對數組或函數類型的實參應用常規指
針轉換。數組實參將當做指向其第一個元素的指針,函數實參當做指向函數類型的指針。

#include <iostream>
using namespace std;
template <typename T>  
T Add(  const T left, T right)
{
    return left + right;
}

template <typename T>
void display( T t)
{
    cout << *t << endl;
}
int main()
{
    int arr[5] = { 1, 2, 3, 4, 5 };
    int a = 10;
    const int& ra = a;

    cout << Add(ra, 1) << endl;  //const轉換
    display(arr); //數組的轉換

    system("pause");
    return 0;
}

函數模板有兩種類型參數:模板參數和調用參數
模板形參名字只能在模板形參之後到模板聲明或定義的末尾之間使用,遵循名字屏蔽規則

#include <iostream>

using namespace std; 
typedef int T;           
template <class T>
T Add(T left, T right)
{
    cout << "left Type = " << typeid(left).name() << endl;  //typeid(left).name() 打印類型名
    return left + right;
}
T gloab;
int main()
{
    cout << Add(1, 2) << endl;
    cout << "gloab Type = " << typeid(gloab).name() << endl;
    system("pause");
    return 0;
}

輸出結果

非模板類型形參是模板內部定義的常量,在需要常量表達式的時候,可以使用非模板類型參數。

#include <iostream>
using namespace std;
template <class T , size_t N>
void display(T (&arr)[N])
{
    for (size_t i = 0; i < N; ++i)
    {
        cout << arr[i] << endl;
    }
}

int main()
{
    int arr[5] = { 1, 2, 3, 4, 5 };
    display(arr);
    system("pause");
    return 0;
}

運行結果

模板形參說明
1、模板形參表使用<>括起來
2、和函數參數表一樣,跟多個參數時必須用逗號隔開,類型可以相同也可以不相同
3、定義模板函數時模板形參表不能爲空
4、模板形參可以是類型形參,也可以是非類型新參,類型形參跟在class和typename後
5、模板類型形參可作爲類型說明符用在模板中的任何地方,與內置類型或自定義類型
使用方法完全相同,可用於指定函數形參類型、返回值、局部變量和強制類型轉換
6、模板形參表中,class和typename具有相同的含義,可以互換,使用typename更加直觀。
但關鍵字typename是作爲C++標準加入到C++中的,舊的編譯器可能不支持。

模板函數重載

1、一個非模板函數可以和一個同名的函數模板同時存在,而且該函數模板還可以被實例
化爲這個非模板函數。
2、對於非模板函數和同名函數模板,如果其他條件都相同,在調動時會優先調動非模板
函數而不會從該模板產生出一個實例。如果模板可以產生一個具有更好匹配的函數,
那麼將選擇模板。
3、顯式指定一個空的模板實參列表,該語法告訴編譯器只有模板才能來匹配這個調用,
而且所有的模板參數都應該根據實參演繹出來。
4、模板函數不允許自動類型轉換,但普通函數可以進行自動類型轉換。

#include <iostream>
using namespace std;
template <class T>
T Max(const T& left, const T& right)
{
    cout << "Max(T)" << endl;
    return (left > right) ? left : right;
}
int Max(const int& left, const int& right)
{
    cout << "Max(int)" << endl;
    return (left > right) ? left : right;
}


int main()
{
    cout << Max<int>(2, 1) << endl;
    cout << Max(2, 1) << endl;
    cout << Max<>(2, 1) << endl;
    cout << Max(2, '1') << endl;
    system("pause");
    return 0;
}

運行結果

模板函數特化

在某些情況下,通用模板定義也木有那麼強大。

#include <iostream>
using namespace std;
template <class T>
int compare(const T s1, const T s2)   
{
    if (s1 > s2)
        return 1;
    else if (s1 < s2)
        return -1;
    else
        return 0;
}

int main()
{
    char* s1 = "dddddd";
    char* s2 = "bbbbbb";
    cout << compare(s1, s2) << endl;
    system("pause");
    return 0;
}

比較字符串顯然不對
實際上他們比較的是地址
那麼就需要模板函數特化

#include <iostream>
using namespace std;
template <class T>
int compare(const T s1, const T s2)   
{
    if (s1 > s2)
        return 1;
    else if (s1 < s2)
        return -1;
    else
        return 0;
}
template<>
int compare<char*>(char*  s1,char*  s2)
{
    return strcmp(s1, s2);
}

int main()
{
     char* s1 = "dddddd";
     char* s2 = "bbbbbb";
    cout << compare(s1, s2) << endl;
    system("pause");
    return 0;
}

這次調用的爲特化過的模板函數

注意:在模板特化版本的調用中,實參類型必須與特化版本函數的形參類型完全匹配,
如果不匹配,編譯器將爲實參模板定義中實例化一個實例。

類模板

模板類也是模板,必須以關鍵字template開頭,後接模板形參表。

template<class 形參名1, class 形參名2, ...class 形參名n>
class 類名
{ ... };

類模板模擬實現Vector:http://blog.csdn.net/l_listen/article/details/78373516
類模板模擬實現List:http://blog.csdn.net/l_listen/article/details/78373654

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章