因为C++模板中有很多概念,总是容易忘记,所以学习了之后,特地总结一下,方便下次复习。
1、类模板和模板类的区别
类模板是一个关于类的模板
模板类是类模板实例化后的实体。
2、特化是针对模板参数更进一步的条件限制所设计出来的特化版本。
模板全特化和偏特化,全特化是把所有模板形参进行限制。 偏特化是把部分形参进行限制。
模板特化和偏特化后,还是一个类模板。
//Grap 为形参 template<typename Grap> class Calculate { public: int GetGirth(const Grap& grap); //获取周长 }; template<typename Grap> int Calculate<Grap>::GetGirth(const Grap& grap) { int iGirth = 0; for (int i = 0; i < grap.GetEdgeCount(); ++i) { iGirth += grap.GetEdgeLength(i); } return iGirth; } class Circle { public: int iR; }; //特化,其中 Circle为实参 template<> class Calculate<Circle> { public: int GetGirth(const Circle& grap); //获取周长 }; //template<> 注意:不需要写这一行 int Calculate<Circle>::GetGirth(const Circle& grap) { return 2 * grap.iR * 3.14; }
3、模板实例化
一个通过具体值替换模板参数,从模板产生普通类、函数或者或者成员函数的过程。
PS 实例化和特化
实例化:查找到最匹配的模板后,根据实参从模板创建出常规类或函数的过程。
特例化:对模板中的部分或全部参数进行特化,定义新模板的过程。
4、类模板和函数模板的区别
a) 类模板没有自动类型推导的使用方式。
b)类模板在模板参数列表中可以有默认参数,既可以缺省。
c)对函数模板,只能全特化,不能偏特化。PS(成员函数可以偏特化)
5、函数模板不能自动类型转换。
void max(T a, T b);
调用 max('a',42.6) 编译错误。
6、函数重载可以完成代替函数偏特化
#pragma once template<typename T1,typename T2> void func(T1 t1, T2 t2) { } #if 0 /* 不能偏特化 */ template<typename T2> void func<int,T2>(int t1, T2 t2) { } #endif //可以通过重载实现偏特化的效果 template<typename T2> void func(int t1, T2 t2) { }
7、类模板偏特化
#pragma once template<typename T1,typename T2> class D { }; template<typename T1> class D<T1,int> { };
8、类模板的显式实例化,在未调用的时候就已经实例化了。
template<typename T> class E { }; //类的显示实例化 template class E<int>;
9、函数模板的显式实例化
template<typename T> void Fun(T t) { } //函数的显式实例化 template void Fun<int>(int);
函数显示实例化可以使编译的时候只产生一个模板类,如果不是显示实例化,则在每个cpp对应的obj中生成一个弱函数,最后链接的时候选择第一个。
模板编译时会进行两阶段检测。
模板编译时,进行和类型参数无关的检测,如未定义的符号等。
模板实例化时,进行类型参数相关的检查。
使用this,若类模板的基类也是类模板,这时在类模板中不能之间通过名称调用从基类继承的成员,而应该通过this->或Base::
tmeplate<typename T> class Base { public: void bar(){}; }; template<typename T> class Derived:public Base<T> { public: void foo() { bar(); //error this->bar(); //ok Base<T>::bar(); //ok } };
SFINAE(替换失败不是错误)
类内的模板函数不能是虚函数,普通函数可以是虚函数。
因为虚函数的通常实现是使用固定大小的虚函数表,每个虚函数有一个入口。然而,模板函数的实例数不是固定的,直到整个程序被编译一遍。