C++之将与参数无关的代码抽离templates(44)---《Effective C++》

条款44:将与参数无关的代码抽离templates

template <typename T,std::size_t n>
class SquareMatrix{
public:
    ...
    void invert();
};

现在,考虑这些代码:

SquareMatrix<double,5) sm1;
...
sm1.invert();

SquareMatrix<double,10> sm2;
...
sm2.invert();

这样将会生成两份invert,这些函数并非完全相同,因为其中一个操作的是5*5矩阵而另一个是10*10的矩阵,但除了常量5和10,两个函数的其他部分完全相同,这是tempalte引出代码膨胀的一个典型例子。

可以发现这两个函数完全相同,只除了一个使用5而另一个使用10,那你会怎么做?以5和10来调用这个带参数的函数,而不重复代码。下面我们来进行第一次对SquareMatrix的修改:

策略1:

template <typename T>
class SquareMatrixBase{
protected:
    ...
    void invert(std::size_t matrixSize);
    ...
};
template <typename T,std::size_t n>
class SquareMatrix:private SquareMatrixBase<T>{
private:
    using SquareMatrixBase<T>::invert;

public:
    ...
    void invert(){this->invert(n);}
};

带参数的invert位于base class SquareMatrixBase中,和SquareMatrix一样,SquareMatrixBase也是个template,不同的是它只对“矩阵元素对象的类型”参数化,不对矩阵的尺寸参数化,因此对于某给定之元素对象那个类型,所有矩阵共享同一个(也是唯一一个)SquareMatrixbase class,它们也将因此共享这唯一一个class内的invert。注意这些函数中我们使用“this->”标记,因为如果不这样做,便如上篇博客中所讲的那样,模板化基类内的函数名称会被derived class掩盖,同时我们这儿使用private继承的原因是base class SquareMatrixBase只是为了帮助derived class SquareMatrix是实现,子类和父类之间不是“is-a”关系。

策略2:
针对SquareMatrixBase::invert的实现,我们该如何操作呢?解决办法是让SquareMatrixBase贮存一个指针,指向矩阵数值所在的内存,而只要它存储了这些东西,也就可能存储矩阵尺寸,如下:

template <typename T>
class SquareMatrixBase{
protected:
    SquareMatrixBase(std::size_t n,T* pMem):size(n),pDate(pMem){

    }
    void setDataPtr(T* ptr){pData=ptr;}
    ...
private:
    std::size_t size;
    T* pData;
};

这允许derived class中决定内存分配方式,这里我们针对derived class有两种分配方式:
1)存储指针数组,这样可能导致对象吱声超级大!!!

template <typename T,std::size_t n>
class SquareMatrix:private SquareMatrixBase<T>{
public:
    SquareMatrix():SquareMtrixBase<T>(n,data){}
    ...
private:
    T data[n*n];
};

2)把每一个矩阵的数据放进heap中,即通过new进行动态内存分配;

template <typename T,std::size_t n>
class SquareMatrix:private SquareMatrixBase<T>{
public:
    SquareMatrix():SquareMatrixBase<T>(n,0),pData(new T[n*n]){
    this->setDataPtr(pData.get());
    }
    ...
private:
    boost::scoped_array<T> pData;
};

PS:
1)non-type template parameters(非类型模板参数):模板参数并不局限于类型,template <<>typename T,int n>或者template <<>typename T,size_t n>等等,第二个就是非类型模板参数!
2)type parameters:标准的类型模板参数,template <<>typename T>。

总结:
1)template生成多个classes和多个函数,所以任何template代码都不应该与某个造成膨胀的template参数产生相依关系;
2)因类型模板参数(non-type template parameters)造成的代码膨胀,往往可以消除,做法是以函数参数或者class成员变量代替template参数;
3)因类型参数(type parameters)而造成的代码膨胀,往往可以降低,做法是让带有完全相同的二进制表搜狐的具现类型共享实现码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值