changed 7 years ago
Linked with GitHub

c++ template

南天門日月卦長


回想之前教過的sort

如果現在有這些陣列需要排序:

  1. int陣列
  2. char陣列
  3. double陣列
  4. float陣列
  5. long long陣列

要寫好幾種sort!!

難道有幾個資料型別就要寫幾個sort嗎?

void int_sort(int s[],int n); void char_sort(char s[],int n); void double_sort(double s[],int n); void float_sort(float s[],int n); void long_long_sort(long long s[],int n); //...

大同小異

這些sort雖然資料型態不一樣
但是程式碼的結構卻是一模一樣的


洪荒時代( < 1990 C.E. )的做法

在本小節中
各位將看到古人們怎麼解決以上的問題
因為有些難度
想跳過的人可以直接去看下一章節的內容


#define

C/C++中#define是很有趣的東西
它可以讓你自訂一些字串來取代原本的字串

詳細請參考教學C++ 巨集


#define範例

如果你寫的程式長這樣:

#define mul(x,y) (x*y) int main(){ cout << mul(3561,2) << '\n'; }

電腦(編譯器)看到的其實是這樣

int main(){ cout << (3561*2) << '\n'; }

好幾行怎麼辦

如果有好幾行要define的話
可以利用反斜線'\'來進行換行

#define swap(a,b){\ auto tmp = a;\ a = b;\ b = tmp;\ } int main(){ int x = 1, y = 2; swap(x, y); cout << x << ' ' << y << endl; }

編譯器視角(調整過)

int main(){ int x = 1, y = 2; { auto tmp = x; x = y; y = tmp; } cout << x << ' ' << y << endl; }

小心使用

各位覺得如果我這樣寫會發生什麼事呢?

#define mul(x,y) (x*y) int main(){ cout << mul(3562-1,1+1) << '\n'; }

編譯器視角

要注意#define只是做字串取代而已

int main(){ cout << (3562-1*1+1) << '\n'; //3562-1*1+1 = 3562!! }

利用 define 製造函數!

#include<iostream> using namespace std; #define max_func(func_name)\ int func_name(int a, int b){\ return a < b ? b : a;\ } max_func(myMax) int main(){ cout << myMax(7122, 2217); }

編譯器視角

#include<iostream> using namespace std; int myMax(int a, int b){ return a < b ? b : a; } int main(){ cout << myMax(7122, 2217); }

產生不同型態的sort

利用define的性質
我們可以稍微簡化產生不同型態sort的方法

#define make_sort(Type, func_name)\ void func_name(Type s[], int n){\ for(int i=1; i<n; ++i)\ for(int j=i; j && s[j]<s[j-1]; --j)\ swap(s[j],s[j-1]);\ } make_sort(int, int_sort) make_sort(double, double_sort)

編譯器視角

void int_sort(int s[], int n){ for(int i=1; i<n; ++i) for(int j=i; j && s[j]<s[j-1]; --j) swap(s[j],s[j-1]); } void double_sort(double s[], int n){ for(int i=1; i<n; ++i) for(int j=i; j && s[j]<s[j-1]; --j) swap(s[j],s[j-1]); }

好難

剛剛教的define還是太麻煩了
而且好難


進入正題

template


template(樣板,模板)

分成


Function template

又稱「通用函式」(Generic Function)
想像 Type 可以是int, double, char
這樣只要寫一個函式就好了!

template<typename Type> void mySort(Type s[], int n){ for(int i=1; i<n; ++i) for(int j=i; j && s[j]<s[j-1]; --j) swap(s[j],s[j-1]); } int main(){ int s[] = {7, 1, 2, 2}; mySort(s, 4); }

使用方法

在你想做成模板的函數前面加上template<>就行了
T會根據呼叫函數時傳入的input變成不同的形態

template<typename T> T func_name(T input){ //do something }

範例

template<typename T> T add(T a, T b){ return a+b; } int main(){ int int_a = 7022,int_b = 100; double d_a = 0.1, d_b = 7.022; cout << add(int_a, int_b) << '\n';// 7122 cout << add(d_a, d_b) << '\n';// 7.122 }

同時有好幾個型態

同時有好幾個型態時可以用逗號','隔開

template<typename T, typename G> int func_name(T a, G b){ //do something }

範例

template<typename T, typename G> int add(T a, G b,double c){ return a+b+c; } int main(){ int int_a = 7022; double d_b = 99.7122; cout << add(int_a, d_b, 0.5) << '\n';// 7122 }

不要讓編譯器有多餘的想像

以下的code會編譯失敗
因為編譯器不知道G到底是甚麼型態

template<typename T, typename G> G add(T a, T b){ G res = a+b;// G到底是甚麼型態? return res; } int main(){ double d_a = 0.1, d_b = 7.022; cout << add(d_a, d_b) << '\n'; }

正確用法

這種情況使用函數時要用角括號<>
告訴編譯器你想用的型態

template<typename T, typename G> G add(T a, T b){ G res = a+b;// G到底是甚麼型態? return res; } int main(){ double d_a = 0.1, d_b = 7.022; cout << add<double, double>(d_a, d_b) << '\n'; cout << add<double, int>(d_a, d_b) << '\n'; cout << add<int, double>(d_a, d_b) << '\n'; }

Class template

又稱「通用類別」(Generic class)
想像 Type 可以是int, double, char
這樣只要寫一個struct/class就好了!

template<typename Type> struct testType{ Type t; int id; }; int main(){ testType<double> data; data.t = 0.7122; data.id = 7122; }

使用方法

在想做成模板的struct/class前面加上template<>
使用時要用**角括號<>**告訴編譯器你T想用的型態

template<typename T> struct testType{ T t; int id; };

範例

template<typename T> struct testType{ T t; int id; testType(T t, int id): t(t), id(id){} }; int main(){ testType<double> data(0.7122, 7122); cout << data.t << ' ' << data.id; }

好幾個型態

當然和Function template一樣可以支援好幾個型態

template<typename T, typename G> struct Jinkela{ T NPK; G shengdiyage; }; Jinkela<int, string> jinkela; int main(){ jinkela.NPK = 30000; jinkela.shengdiyage = "American.shengdiyage"; }

下一步,STL!

在下一章節中,我們會介紹強大的STL
標準模板庫(Standard Template Library)
會用到大量template的概念
一定要熟悉喔

Select a repo