標題上說「將與參數無關的代碼抽離template」,這裏的參數既能夠指類型,也能夠是非類型,咱們先來看看非類型的狀況。算法
假定咱們要爲矩陣寫一個類,這個矩陣的行列元素個數相等,是一個方陣,於是咱們能夠對之求逆運算。由於方陣的元素能夠有多種類型,同時方陣的維數(方陣大小)也能夠不一樣,像下面這樣,咱們使用了模板:函數
1 template <class T, size_t n> 2 class SquareMatrix 3 { 4 public: 5 void Invert(); 6 }; 7 8 int main() 9 { 10 SquareMatrix<int, 10> a; 11 SquareMatrix<int, 5> b; 12 }
模板既能夠指定類型,也能夠指定其餘參量,好比這裏的size_t,用來表示方陣的維數。程序看起來是沒有問題的,編譯也是經過的,但從代碼優化上看,仍是有空間能夠作的。a和b雖然都是元素爲int型的方陣,但由於方陣維數不一樣,於是生成了兩個Invert函數,這兩個Invert函數的代碼只是在循環個數上不一樣(取覺於方陣維數n),但算法思想徹底是同樣的。工具
爲了防止編譯器生成冗餘的代碼,咱們能夠將Invert抽離這裏,變成一個以n爲參數的函數,像下面這樣:優化
1 class SquareMatrixBase 2 { 3 public: 4 SquareMatrixBase(T* p) : DataPointer(p){} 5 void Invert(size_t n){} 6 private: 7 T* DataPointer; 8 }; 9 10 11 template <class T, size_t n> 12 class SquareMatrix: private SquareMatrixBase<T> 13 { 14 public: 15 SquareMatrix() : SquareMatrixBase(Data) 16 {} 17 void Invert() 18 { 19 SquareMatrixBase::Invert(n); 20 } 21 private: 22 T Data[n * n]; 23 };
這裏咱們定義了一個BaseSquareMatrix類,這個類能夠視爲一個工具類,由於SquareMatrix是private繼承於它的,咱們把算法一致、只與維數n相關的算法函數都放在BaseSquareMatrix中,且將n做爲它的Invert()函數的形參,爲了使BaseSquareMatrix能夠訪問數據,從而求逆運算,咱們聲明瞭它的成員指針,這個指針將會在構造時指向子類的數據存儲空間。spa
子類SquareMatrix沒有大變化,只是在Invert的時候,用了一句代碼就搞定了——調用父類的Invert函數,並把維數n傳過去。指針
這樣在main函數中,針對類型都是int,但矩陣維數不一樣的狀況,Invert中生成的冗餘代碼很是少(只有一句話),父類也由於模板參數與維數沒法,因此也只生成一份。從這個角度來看,將與參數無關的代碼抽離template起到了減小代碼冗餘度的優化做用。code
目前只是說將與類型無關的代碼進行抽離(造一個父類,把算法相同的部分提取出來,放到父類),對於不一樣類型,其實也能夠經過void*來實。好比STL,要想令咱們使用list<int*>,list<const int*>生成的代碼冗餘度保持很低,這就須要在相應的函數裏面,將之鏈到父類的一個公共實現版本里面,這個版本的形參是void*。blog
最後總結一下:繼承
1. Template生成多個classes與多個函數,因此任何template代碼都不應與某個形成膨脹的template參數產生相依關係。編譯器
2. 因非類型模板參數而形成的代碼膨脹,每每能夠消除,作法是以函數參數或者class成員變量替換template參數。
3. 因類型而形成的代碼膨脹,也能夠下降,作法是讓帶有徹底相同二進制表述的具現類型共享實現碼。