面向对象编程世界总是以显式接口(explicit interface)和运行期多态(runtime polymorphism)解决问题。Templates及泛型编程以隐式接口(implicit interface)和编译期多态(compile-time polymorphism)
在template中执行于类型(T)对象身上的操作便是T必须支持的一组隐式接口。
以不同的template参数具现化function templates,会导致调用不同的函数,这便是所谓的编译期多态(compile-time polymorphism)。
将与参数无关的代码抽离templates
· Templates生成多个classes和多个函数,所以任何template代码都不该与某个造成膨胀的template 参数产生相依关系。
· 因非类型模板参数(non-type template parameters)而造成的代码膨胀,往往可以消除,做法是以函数参数或class成员变量替换template参数。
· 因类型参数(type parameters)而造成的代码膨胀,往往可降低,做法是让带有完全相同二进制表述(binary representations)的具体类型(instantiation types)共享实现码。
例如在许多平台上 int和 long有相同的二进制表述,templates被具现化为int和long两个版本。所以像vector
例子:解决因非类型模板参数而造成的代码膨胀
template<typenameT>
class SquareMatrixBase{
protected:
SquareMatrixBase(std::size_tn,T* pMem) :size(n), pData(pMem){}
void setDataPtr(T*ptr){ pData =ptr; }
protected:
void invert(std::size_tmatrixSize){
//do something
};
private:
std::size_t size;
T* pData;
};
template<typenameT, std::size_t n>
class SquareMatrix: privateSquareMatrixBase<T>
{
public:
SquareMatrix(): SquareMatrixBase<T>(n, data){}
void invert() {this->invert(n); }
private:
using SquareMatrixBase<T>::invert;
private:
T data[n*n];
};
void main()
{
SquareMatrix<int, 10> matrix;
matrix.invert();
}
在template实参推导过程中从不将隐式类型转换函数纳入考虑。(这样的转换在函数调用过程中确实被使用,但在能够调用一个函数之前,首先必须知道那个函数存在。而为了知道它,必须先为相关的function template推导出参数类型,然后才可将适当的函数具现化出来。然而template实参推导过程中并不考虑采纳“通过构造函数而发生的”隐式类型转换。)
当我们编写一个class template,而它所提供之“与此template相关的”函数支持“所有参数之隐式类型转换”时,请将那些函数定义为“class template内部的friend函数”。Class templates并不依赖template实参推导(后者只施行于function templates身上)。
注:这项技术的一个趣味点是,我们虽然使用friend,却与friend的传统用途“访问class的non-public成分”毫不相干。为了让类型转换可能发生于所有实参身上,我们需要一个non-member函数;为了令这个函数被自动具现化,我们需要将它声明在class内部;而在class内部声明non-member函数的唯一办法就是:令它成为一个friend。
编译期绑定 ---overloading,在编译期对类型执行if…else测试
Template使得“类型相关信息”在编译期可用。
运行时绑定—overriding,在运行期对类型执行if…else测试
Template metaprogramming (TMP,模板元编程)可将工作由运行期移往编译期,因而得以实现早期错误侦测和更高的执行效率。可被运来生成policy–based design(设计模式如Strategy, Observer, Visitor)之TMP based技术的客户定制代码。
TODO: templates的深入系统研究和其各类特化版本。