侧边栏壁纸
博主头像
如此肤浅

但行好事,莫问前程!

  • 累计撰写 52 篇文章
  • 累计创建 6 个标签
  • 累计收到 6 条评论

目 录CONTENT

文章目录

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

如此肤浅
2022-06-10 / 0 评论 / 0 点赞 / 36 阅读 / 1,485 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-06-10,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

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

问题描述

如果 templates 使用不当可能会导致代码膨胀:其二进制码带着重复(或几乎重复)的代码、数据。

在 non-template 代码中,重复的代码清晰可见:你可以看到两个函数或两个类直接所有重复的代码。然而在 template 代码中,重复是隐晦的:毕竟只有一份 template 源码,所以必须自己去感受当 template 被具化多次时可能发生的重复。

例如:

// n x n矩阵
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,这两个函数可能只有与参数有关的数据会不同,其他的部分完全相同。这就是 template 引出代码膨胀的一个典型例子。

解决方式

如果你看到两个函数完全相同,只除了一个使用了5而一个使用了10,你本能地会想创建一个函数,将5和10作为参数传进去,而不使用重复的代码。因此对上面的 SquareMatrix 进行第一次修改:

template<typename T>
class SquareMatrixBase { // 与尺寸无关的base class
protected:
	...
    void invert(std::size_t matrixSize); // 以给定的尺寸求逆矩阵
    ...
};
template<typename T, std::size_t>
class SquareMatrix: private SquareMatrixBase<T> {
private:
	// 避免遮掩base版的invert,见条款33
	using SquareMatrixBase<T>::invert;
public:
	...
    void invert() { this->invert(n); } // 调用base class的invert
};

上述代码中,带参数的 invert 位于 base class SquareMatrixBase 中。SquareMatrixBase 也是一个 template,但它只对“矩阵元素对象的类型”参数化,不对矩阵的尺寸参数化。因此对于某给定的元素对象类型,所以矩阵共享一个 SquareMatrixBase class。它们也将因此共享这个唯一的 class 内的 invert。

调用基类的 invert 时,如果不使用“this->”记号,模板化基类(如 SquareMatrixBase< T>)内的函数名称会被派生类掩盖(见条款43)。也请注意,上述代码的继承关系时 private,这说明此处的 base class 只是为了帮助 derived class 实现,而不是 is-a 关系。

0

评论区