首先,模板是创建类或函数的蓝图或公式,如vector<T>等各类容器是最基本的模板定义。
下面是我学习过程中记录的一些要点感悟:
1. 在模板形参表内声明类型形参时template<typename T>中的 typename 换成 class 是没有区别的,只是typename是标准c++的组成部分,用起来也更直观一些。
2.若函数模板返回值出现两可的选择的时候,有两种方案
template <typename T1,typename T2> ??? Swap(T1,T2);
(1)强制函数将较小的那个形参类型转换成希望作为结果使用的类型,其中强制转换符static_cast< T >( )是一个特别好玩的东西。
int i;short s;
sum(static_cast<int>(s),i);
(2)引入一个另外的模板形参做返回值类型。
template <typename T1,typename T2,typename T3>
T1 Swap(T2,T3);
int value=Swap<int>(i,s);
一般把返回值的模板形参放在最左,因为显式模板实参从左至右与对应模板形参相匹配,只有右侧的形参的显示模板实参可以省略,若Swap函数被这样定义
template <typename T1,typename T2,typename T3>
T3 Swap(T2,T1);
则必须为所有三个实参指定形参
int value=Swap<short,int,int>(i,s);
3.编译器不会为类中使用的其他模板的模板形参进行实际的推断,因此,在生命友元的对象时必须显式指定类型实参,省略会报错。
4.若直接将一个类模板设为另一个类模板的友元。那么,第一个模板的任意实例的任意对象都可以访问第二个模板类的任意私有元素。这样做显然是不科学的,那么,类可以只赋予特定实例的访问权。
template <typename T> class Foo;
template <typename T> void temp(const T&);
template <typename Type> class Bar
{
friend class Foo<char*>;
friend void temp<char*>(char* const&)
}
而更常见的声明是
template <typename T> class Foo;
template <typename T> void temp(const T&);
template <typename Type> class Bar
{
friend class Foo<Type>;
friend void temp<Type>(const Type&)
}
5.友元模板类的声明依赖性。非模板类作为其他类友元不需要前置声明,而友元模板类必须存在前置声明,否则将会认为wasn't declared as a template。
template <typename T> class A;
template <typename T> class B
{
public:
friend class A<T>; //ok
friend class C; //ok: C is a nontemplate class
friend class D<T> //error: D wasn't declared as a template.
}
6.当成员模板是类模板的成员是,类外定义必须包含类模板形参以及自己的模板形参,首先是类模板形参表,然后是成员自己的模板形参表。
template <typename T> template <typename It>
void A<T>::Swap<It t1,It t2>
{
...
}
7.若模板类中有static成员,则类的每个实例化都有自己的static成员。注意:不是每个对象,是每个实例。
8.关于特化,还有很多要说的,,,睡了,,,困。