标题上说“将与参数无关的代码抽离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. 因类型而形成的代码膨胀,也能够下降,作法是让带有彻底相同二进制表述的具现类型共享实现码。