条款44:将与参数无关的代码剥离template
使用template时,不小心的时候可能就会带来代码膨胀的问题:
1 template<typename T, 2 std::size_t n> 3 class SquareMatrix{ 4 public: 5 void invert(); 6 }; 7 //而对于下面两份模版实例化 8 SquareMatrix<double, 10> ma10; 9 SquareMatrix<double, 5 > ma5;
这两个实例化除了特殊的数字之外,其他的所有参数代码都是一样的,这就带来了所谓的代码膨胀,而避免上面这种状况的一个有效办法就是,让这个带有typename的template作为基类:
1 template<typename T> 2 class SquareMatrixBase{ 3 protected: 4 void invert(std::size_t matrixSize);//这里的size_t相当于减少了代码实例化的机会 5 };
1 template<typename T, 2 std::size_t n> 3 class SquareMatrix : private SquareMatrixBase<T>{ 4 private: 5 using SquareMatrixBase<T>::invert; 6 public: 7 ... 8 void invert(){this->invert(n);}//这里制造了inline调用,降低调用的开销,使用this是为了访问这个成员被模板的影响所遮盖 9 }
但是这里还有个问题,就是derived class中使用的数据T 是存在与base class中的。
一种方法是给基类的数据一个private指针:
1 template<typename T> 2 class SquareMatrixBase{ 3 protected: 4 SquareMatrixBase(std::size_t n, T *pMem): 5 size(n), pData(pMem){} 6 void setDataPtr(T * ptr){pData =ptr;} 7 ... 8 private: 9 T data[n*n]; 10 };
还有一种就是动态分配内存,不过大体的过程是一样的。
使用这些方法,就使得不同大小的矩阵只是拥有者单一版本的invert。
这个问题讨论的主要是非类型模板参数带来的代码膨胀
小结:
Template生成多个函数以及多个class,所以template的代码都不应该与某个造成依赖的参数产生关系
上面讨论的是非类型模板参数带来的膨胀,往往可以正常消除