目錄
概念
?編輯
?語法
函數模板
類模板
?非類型模板參數
模板的特化
函數模板特化
類模板特化
全特化
偏特化
分離編譯
概念
模板是C++中非常厲害的設計,模板把通用的邏輯剝離出來,讓不同的數據類型可以復用同一種模板的邏輯,甚至可以讓不同的邏輯復用同一種模板邏輯(仿函數的設計)
【C++】詳解STL的適配器容器之一:優先級隊列 priority_queue-CSDN博客
模板可以幫助我們實現代碼的重用和泛化,提高代碼的靈活性和可維護性。
STL的容器就是對模板很好的運用,可參考
【C++】詳解STL容器之一的 vector-CSDN博客
【C++】詳解STL的容器之一:list-CSDN博客
?語法
template <typename T> //可以寫成template <class T>
class MyClass {// ...
};template <typename T> //可以寫成template <class T>
T add(T a, T b) {return a + b;
}
在上面的示例中,MyClass
是一個類模板,add
是一個函數模板。通過使用 typename
或 class
關鍵字聲明模板參數,T 就是未知類型
函數模板
通過使用函數模板,我們可以定義一種通用的函數,可以根據實際需要傳不同的數據復用函數模板
函數模板的語法格式如下:
template <typename T>
返回類型 函數名(參數列表) {// 函數體
}
其中,template關鍵字表示這是一個函數模板,<typename T>表示定義了一個類型參數T,可以根據需要使用不同的類型來替換T,返回類型表示函數的返回類型,函數名表示函數的名稱,參數列表表示函數的參數列表。
在函數模板中,可以使用類型參數T作為函數的參數類型、返回類型或局部變量的類型。例如:
template <typename T>
T max(T a, T b) {return (a > b) ? a : b;
}
上述代碼定義了一個函數模板max,它接受兩個參數a和b,這兩個參數的類型都是T,并且返回類型也是T
使用函數模板時,需要在函數名后面加上尖括號<>,并在其中指定具體的類型。例如:
int result1 = max<int>(3, 5); // 使用int類型實例化函數模板
double result2 = max<double>(3.14, 2.71); // 使用double類型實例化函數模板
max<int>表示使用`int`類型實例化max函數模板,max<double>表示使用double類型實例化max函數模板。傳不同的參數示例化的函數是不同的
函數模板還可以有多個類型參數,可以使用逗號分隔它們。例如:
template <typename T1, typename T2>
void printPair(T1 a, T2 b) {cout << "(" << a << ", " << b << ")" << endl;
}
使用函數模板時,需要指定每個類型參數的具體類型。例如:
printPair<int, double>(3, 3.14); // 使用int和double類型實例化函數模板
在上述代碼中,printPair<int, double>表示使用int類型和double類型實例化printPair函數模板。
總結起來,函數模板是一種通用的函數定義,可以用于多種不同類型的參數。通過使用函數模板,可以編寫一次代碼,然后在不同的地方使用不同的數據類型進行調用。
類模板
通過使用類模板,我們可以定義一種通用的類模板,可以根據實際需要在不同場景下傳入不同的類型實例化出不同的類。
類模板的語法格式如下:
template <typename T> //可以寫成template <class T>
class 類名 {// 成員變量和成員函數的定義
};
在類模板中,可以使用類型參數T作為成員變量的類型、成員函數的參數類型或返回類型。例如:
template <typename T>
class Stack {
private:T* data;int size;
public:Stack(int capacity) {data = new T[capacity];size = 0;}void push(T value) {data[size++] = value;}T pop() {return data[--size];}
};
上述代碼定義了一個類模板Stack,它有一個私有成員變量data和size,分別表示存儲數據的數組和當前棧的大小。類模板還有兩個公有成員函數push和pop,分別用于向棧中壓入元素和彈出棧頂元素。
使用類模板時,需要在類名后面加上尖括號<>,并在其中指定具體的類型。例如:
Stack<int> intStack(10); // 使用int類型實例化類模板
Stack<double> doubleStack(5); // 使用double類型實例化類模板
不然會報如下錯誤
Stack<int>表示使用int類型實例化Stack類模板,Stack<double>表示使用double類型實例化Stack類模板。根據實際的類型參數,編譯器會生成相應的類定義。
類模板還可以有多個類型參數,可以使用逗號分隔它們。例如:
template <typename T1, typename T2>
class Pair {
private:T1 first;T2 second;
public:Pair(T1 a, T2 b) {first = a;second = b;}void print() {cout << "(" << first << ", " << second << ")" << endl;}
};
使用類模板時,需要指定每個類型參數的具體類型。例如:
Pair<int, double> p1(3, 3.14); // 使用int和double類型實例化類模板
Pair<string, int> p2("Hello", 5); // 使用string和int類型實例化類模板
?非類型模板參數
模板參數分為:類型形參與非類型形參類型形參:出現在模板參數列表中,跟在class或者typename之類的參數類型名稱非類型形參:就是用一個常量作為類(函數)模板的一個參數,在類(函數)模板中可將該參數當成常量來使用
// 定義一個模板類型的靜態數組template<class T, size_t N = 10>class array{public:T& operator[](size_t index){return _array[index];}const T& operator[](size_t index)const{return _array[index];}size_t size()const{return _size;}bool empty()const{return 0 == _size;}private:T _array[N];size_t _size;};
模板的特化
概念:
函數模板特化
必須要先有一個基礎的函數模板關鍵字 template 后面接一對空的尖括號 <>函數名后跟一對尖括號,尖括號中指定需要特化的類型函數形參表 :? 必須要和模板函數的基礎參數類型完全相同
// 函數模板 -- 參數匹配
template<class T>
bool Less(T left, T right)
{return left < right;
}
// 對Less函數模板進行特化
template<>
bool Less<Date*>(Date* left, Date* right) //Date是日期類
{return *left < *right;
}
下面是測試
關于日期類小編也寫了一篇文章:【C++】如何用C++寫一個日期計算器-CSDN博客
類模板特化
全特化
template<class 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;
};
下面是測試
偏特化
template<class T1, class T2>
class Data
{
public:Data() {cout<<"Data<T1, T2>" <<endl;}
private:T1 _d1;T2 _d2;
};
template <class T1>
class Data<T1, int>
{
public:Data() {cout<<"Data<T1, int>" <<endl;}
private:T1 _d1;int _d2;
};
template<class T1, class T2>
class Data
{
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:
T1 _d1;T2 _d2;
};
//兩個參數偏特化為引用類型
template <typename T1, typename T2>
class Data <T1&, T2&>
{
public:Data(const T1& d1, const T2& d2): _d1(d1), _d2(d2){cout<<"Data<T1&, T2&>" <<endl;}private:const T1 & _d1;const T2 & _d2; };
分離編譯
下面了解即可
C/C++程序要運行要經歷以下步驟
預處理--->?編譯---> 匯編---> 鏈接
預處理:將頭文件展開
編譯:頭文件不參與編譯,編譯主要是檢查語法錯誤,多個源文件單獨分開編譯
匯編:將文本文件翻譯成二進制文件
鏈接:將多個編譯好的源文件合成一個
如果將模板聲明和定義分離會報鏈接錯誤
可參考下面這位大佬的文章
為什么C++編譯器不能支持對模板的分離式編譯-CSDN博客