读书笔记_Effective_C++_条款四十四:将与参数无关的代码抽离template

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

相关文章
相关标签/搜索