--- slideOptions: transition: slide --- <!-- .slide: data-transition="fade-in convex-out" --> # c++ template 南天門日月卦長 --- ## 回想之前教過的sort 如果現在有這些陣列需要排序: 1. int陣列 2. char陣列 3. double陣列 4. float陣列 5. long long陣列 6. ... ---- ## 要寫好幾種sort!! 難道有幾個資料型別就要寫幾個sort嗎? ```cpp= 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雖然資料型態不一樣 但是程式碼的結構卻是一模一樣的 --- <!-- .slide: data-transition="fade-in convex-out" --> ## 洪荒時代( < 1990 C.E. )的做法 在本小節中 各位將看到古人們怎麼解決以上的問題 因為有些難度 想跳過的人可以直接去看[下一章節](#/6)的內容 --- ## ```#define``` C/C++中```#define```是很有趣的東西 它可以讓你自訂一些字串來取代原本的字串 詳細請參考教學[C++ 巨集](http://en.cppreference.com/w/cpp/preprocessor/replace) ---- ## #define範例 如果你寫的程式長這樣: ``` cpp= #define mul(x,y) (x*y) int main(){ cout << mul(3561,2) << '\n'; } ``` 電腦(編譯器)看到的其實是這樣 ``` cpp= int main(){ cout << (3561*2) << '\n'; } ``` ---- ## 好幾行怎麼辦 如果有好幾行要define的話 可以利用**反斜線**```'\'```來進行換行 ```cpp= #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; } ``` ---- ## 編譯器視角(調整過) ```cpp= int main(){ int x = 1, y = 2; { auto tmp = x; x = y; y = tmp; } cout << x << ' ' << y << endl; } ``` ---- ## 小心使用 各位覺得如果我這樣寫會發生什麼事呢? ```cpp= #define mul(x,y) (x*y) int main(){ cout << mul(3562-1,1+1) << '\n'; } ``` ---- ## 編譯器視角 要注意```#define```只是做字串取代而已 ```cpp= int main(){ cout << (3562-1*1+1) << '\n'; //3562-1*1+1 = 3562!! } ``` --- ## 利用 define 製造函數! ```cpp= #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); } ``` ---- ## 編譯器視角 ```cpp= #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的方法 ```cpp= #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) ``` ---- ## 編譯器視角 ```cpp= 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 --- <!-- .slide: data-transition="convex-in convex-out" --> ## template(樣板,模板) 分成 * [Function template](#/7) * [Class template](#/8) --- ## Function template 又稱「通用函式」(Generic Function) 想像 Type 可以是int, double, char ... 這樣只要寫一個函式就好了! ```cpp= 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變成不同的形態 ```cpp= template<typename T> T func_name(T input){ //do something } ``` ---- ## 範例 ```cpp= 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 } ``` ---- ## 同時有好幾個型態 同時有好幾個型態時可以用**逗號**```','```隔開 ```cpp= template<typename T, typename G> int func_name(T a, G b){ //do something } ``` ---- ## 範例 ```cpp= 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到底是甚麼型態 ```cpp= 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'; } ``` ---- ## 正確用法 這種情況使用函數時要用**角括號```<>```** 告訴編譯器你想用的型態 ```cpp= 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就好了! ```cpp= 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想用的型態 ```cpp= template<typename T> struct testType{ T t; int id; }; ``` ---- ## 範例 ```cpp= 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一樣可以支援好幾個型態 ```cpp= 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的概念 一定要熟悉喔