条款44:将与参数无关的代码抽离模板(Factor parameter-independent code out of templates)

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

1.1 提出问题

使用模板可能会导致代码膨胀:二进制文件中有重复(或几乎重复)的代码或数据。

template<typename T, std::size_t n> // nxn个T类型对象矩阵的模板,n为非类型参数
class SquareMatrix { 
public:
    ...
    void invert(); // 对矩阵求逆
};
//这里将实例化两个invert副本
SquareMatrix<double, 5> sm1;
...
sm1.invert(); // 调用 SquareMatrix<double, 5>::invert
SquareMatrix<double, 10> sm2;
...
sm2.invert(); // 调用 SquareMatrix<double, 10>::invert

1.2 解决办法

为解决重复问题,下面是我们的第一次尝试:

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; // 避免隐藏invert的基类版本
public:
    ...
    void invert() { this->invert(n); } // 内联调用基类版本的invert
}; 

SquareMatrixBase::invert通过参数知道矩阵的大小,但它如何知道特定矩阵的数据在哪里呢?如果还是通过函数的参数传入指向数据的指针,将可能需要在不同的函数里重复传入相同的指针。所以我们决定把数据的(连同大小)都存在基类:

template<typename T>
class SquareMatrixBase {
protected:
    SquareMatrixBase(std::size_t n, T* pMem) //存储矩阵大小和数据的指针
        : size(n), pData(pMem) {} 
    void setDataPtr(T* ptr) { pData = ptr; } // 为pData赋值
    ...
private:
    std::size_t size; 	// 矩阵大小
    T* pData; 			// 指向矩阵数据的指针
};
template<typename T, std::size_t n>
class SquareMatrix : private SquareMatrixBase<T> {
public:
    SquareMatrix()          
	: SquareMatrixBase<T>(n, data) // 将矩阵大小和数据的指针传送给基类
    {} 
    ...
private:
    T data[n * n];
};

1.3 其他办法

另一种方法是将每个矩阵的数据放到堆中:

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:
    std::unique_ptr<T> pData; 
}; 

1.4 总结

  1. 模板会生成多个类和多个函数,因此任何不依赖于模板参数的模板代码都会导致代码膨胀。
  2. 通过将模板参数替换为函数参数或类数据成员,通常可以消除由非类型模板参数引起的膨胀。
  3. 通过共享具有相同二进制表示方式的类型的实例化,可以减少类型参数导致的膨胀。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值