1,預備知識:
1,模板參數可以是數值型參數(非類型參數):
1,代碼示例:
1 template <typename T, int N> 2 void func() 3 { 4 T a[N]; // 使用模板參數定義局部數組; 5 } 6 7 func<double, 10>(); // 使用模板時,數值型參數必須是常量,不能是變量;
2,數值型模板參數的限制:
1,變量不能作為模板參數;
1,是變量的話就不滿足准確確定的這個本質;
2,浮點數不能作為模板參數;
1,浮點數本身不精確;
3,類對象不能作為模板參數;
1,類對象編譯時不能唯一確定的,同變量一樣;
3,數值型參數本質:模板參數是在編譯階段被處理的單元,因此,在編譯階段必須准確無誤的唯一確定;
2,有趣的面試題:
1,用你覺得最高效的方法求 1 + 2 + 3 + ... + N 的值;
1,等差數列和的方式;
2,見下面實例;
3,數值型模板參數編程實驗:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 /* 驗證上面的預備知識 */ 7 template 8 < typename T, int N > // 這里用成 double 后,編譯器顯示:error: 'double' is not a valid type for a template constant parameter 9 void func() 10 { 11 T a[N] = {0}; 12 13 for(int i=0; i<N; i++) 14 { 15 a[i] = i; 16 } 17 18 for(int i=0; i<N; i++) 19 { 20 cout << a[i] << endl; 21 } 22 } 23 24 /* 用最高效的方法驗證從 1 加到 n 的和;不用循環和等差數列求和公式 */ 25 template 26 < int N > 27 class Sum 28 { 29 public: 30 // static const int VALUE = 0; // static 后是想定義常量,被 static 修飾后要么放入符號表、要么放到全局數據區; 這個時候 VALUE 已經確定了值,所以直接進入符號表(符號表存儲在哪里呢);又因為 VALUE 被 static 修飾了,所以 VALUE 被放入全局數據區; 31 static const int VALUE = Sum<N-1>::VALUE + N; // 遞歸定義 32 }; 33 34 /* 定義上述模板類的特化實現,實現遞歸出口 */ 35 template 36 < > 37 class Sum < 1 > 38 { 39 public: 40 static const int VALUE = 1; 41 }; 42 43 int main() 44 { 45 func<int, 10>(); // 打印 0 到 9 這十個數字;這里如果模板參數類型為 double,編譯器顯示:error: no matching function for call to 'func()'; 46 47 int a = 10; 48 func<int, a>(); // 在這一行編譯器顯示: 49 // error: 'a' cannot appear in a constant-expression 50 // error: no matching function for call to 'func()' 51 52 cout << "1 + 2 + 3 + ... + 10 = " << Sum<10>::VALUE << endl; // 55;這里沒有加減乘除法,也沒有函數調用和循環,這里VALUE 是常量,並在編譯的時候已經確定,這里效率是最高的; 53 cout << "1 + 2 + 3 + ... + 100 = " << Sum<100>::VALUE << endl; // 5050 54 55 return 0; 56 }
1,這里的相加求和是在編譯器編譯程序的時候完成的,編譯完程序后,要求的和的值已經確定,在運行的時候,就直接可以訪問這個值,不需要做任何的運算和循環,因此效率最高;
2,這個最高效的求和依賴了模板技術、模板特化技術、數值型模板參數技術;
3,可以舉一反三,得到更多高效的程序寫法;
4,數組模板類編程實驗:
1,Array.h 文件:
1 #ifndef _ARRAY_H_ // 防止多次包含頭文件; 2 #define _ARRAY_H_ 3 4 template 5 < typename T, int N > // 數組元素的類型和大小; 6 class Array 7 { 8 T m_array[N]; // 定義一個實際的數組; 9 public: 10 int length(); 11 bool set(int index, T value); 12 bool get(int index, T& value); 13 T& operator[] (int index); 14 T operator[] (int index) const; // 數組類對象有可能是 const 對象,這個時候就只能調用 const 函數,所以要定義這個;const 函數只能返回值,不能返回引用; 15 virtual ~Array(); // 有可能被繼承 16 }; 17 18 /* 模板類要放在一個文件中,所以實現在下面實現 */ 19 20 template 21 < typename T, int N > 22 int Array<T, N>::length() 23 { 24 return N; 25 } 26 27 template 28 < typename T, int N > 29 bool Array<T, N>::set(int index, T value) 30 { 31 bool ret = (0 <= index) && (index < N); 32 33 if( ret ) 34 { 35 m_array[index] = value; 36 } 37 38 return ret; 39 } 40 41 template 42 < typename T, int N > 43 bool Array<T, N>::get(int index, T& value) 44 { 45 bool ret = (0 <= index) && (index < N); 46 47 if( ret ) 48 { 49 value = m_array[index]; 50 } 51 52 return ret; 53 } 54 55 template 56 < typename T, int N > 57 T& Array<T, N>::operator[] (int index) 58 { 59 return m_array[index]; 60 } 61 62 template 63 < typename T, int N > 64 T Array<T, N>::operator[] (int index) const 65 { 66 return m_array[index]; 67 } 68 69 template 70 < typename T, int N > 71 Array<T, N>::~Array() 72 { 73 74 } 75 76 #endif
2,應用:
1 #include <iostream> 2 #include <string> 3 #include "Array.h" 4 5 using namespace std; 6 7 int main() 8 { 9 Array<double, 5> ad; 10 11 for(int i=0; i<ad.length(); i++) 12 { 13 ad[i] = i * i; 14 } 15 16 for(int i=0; i<ad.length(); i++) 17 { 18 cout << ad[i] << endl; 19 } 20 21 return 0; 22 }
5,堆數組模板類編程實驗:
1,HeapArray.h 文件:
1 #ifndef _HEAPARRAY_H_ 2 #define _HEAPARRAY_H_ 3 4 template 5 < typename T > 6 class HeapArray 7 { 8 private: 9 int m_length; 10 T* m_pointer; 11 12 HeapArray(int len); 13 HeapArray(const HeapArray<T>& obj); 14 bool construct(); 15 public: 16 static HeapArray<T>* NewInstance(int length); 17 int length(); 18 bool get(int index, T& value); 19 bool set(int index ,T value); 20 T& operator [] (int index); 21 T operator [] (int index) const; // 有可能有 const 對象; 22 HeapArray<T>& self(); 23 ~HeapArray(); // 這個時候構造函數是 private 的,也就是 HeapArray 類不希望被繼承,所以說沒有必要將它聲明為 virtual 的; 24 }; 25 26 /* 實現要在同一個文件中 */ 27 28 template 29 < typename T > 30 HeapArray<T>::HeapArray(int len) 31 { 32 m_length = len; 33 } 34 35 template 36 < typename T > 37 bool HeapArray<T>::construct() 38 { 39 m_pointer = new T[m_length]; 40 41 return m_pointer != NULL; 42 } 43 44 template 45 < typename T > 46 HeapArray<T>* HeapArray<T>::NewInstance(int length) 47 { 48 HeapArray<T>* ret = new HeapArray<T>(length); 49 50 if( !(ret && ret->construct()) ) 51 { 52 delete ret; 53 ret = 0; 54 } 55 56 return ret; 57 } 58 59 template 60 < typename T > 61 int HeapArray<T>::length() 62 { 63 return m_length; 64 } 65 66 template 67 < typename T > 68 bool HeapArray<T>::get(int index, T& value) 69 { 70 bool ret = (0 <= index) && (index < length()); 71 72 if( ret ) 73 { 74 value = m_pointer[index]; 75 } 76 77 return ret; 78 } 79 80 template 81 < typename T > 82 bool HeapArray<T>::set(int index, T value) 83 { 84 bool ret = (0 <= index) && (index < length()); 85 86 if( ret ) 87 { 88 m_pointer[index] = value; 89 } 90 91 return ret; 92 } 93 94 template 95 < typename T > 96 T& HeapArray<T>::operator [] (int index) 97 { 98 return m_pointer[index]; 99 } 100 101 template 102 < typename T > 103 T HeapArray<T>::operator [] (int index) const 104 { 105 return m_pointer[index]; 106 } 107 108 template 109 < typename T > 110 HeapArray<T>& HeapArray<T>::self() 111 { 112 return *this; 113 } 114 115 template 116 < typename T > 117 HeapArray<T>::~HeapArray() 118 { 119 delete[]m_pointer; 120 } 121 122 #endif
2,應用:
1 #include <iostream> 2 #include <string> 3 #include "HeapArray.h" 4 5 using namespace std; 6 7 int main() 8 { 9 HeapArray<char>* pai = HeapArray<char>::NewInstance(10); 10 11 if( pai != NULL ) 12 { 13 HeapArray<char>& ai = pai->self(); 14 15 for(int i=0; i<ai.length(); i++) 16 { 17 ai[i] = i + 'a'; 18 } 19 20 for(int i=0; i<ai.length(); i++) 21 { 22 cout << ai[i] << endl; 23 } 24 } 25 26 delete pai; 27 28 return 0; 29 }
6,小結:
1,模板參數可以是數值型參數;
2,數值型模板參數必須在編譯期間唯一確定;
3,數組類模板是基於數值型模板參數實現的;
4,數組類模板是簡易的線性表數據結構;