模板是一个非常有用的东西,可以让我们写一次代码产生出不同的版本以应对不同的数据类型,原理是在具体调或者是在编译时产生不同的版本。
使用格式为:
template<class T> or template<typename T>
这里的class与typename 没有区别,前者要老一些,后者更直观一点的表明后面跟的是个类型名。
1.函数模板:例:template<class T> compare( const T &a, const T &b){ }
说明:模板声明中跟在class and typename 后面的叫类型形参,跟在其它声明比如 int 或是其它自定义类型后面的叫作非类型形参。
使用函数模板时可以直接调用如:compare(1,3);编译器会自动生成相应的版本。
inline 模板函数的声明中inline 要放在<>后,如:template<class T> inline T compare( const T &a, const T &b){ }
2. 类模板:template<class T> class A{}
类模板的使用与函数模板有所不同,在调用类模板时必须显式的指定形参,如我们定义的A的使用:
A< int > ai; A< char > ac; A< vector<double> > av; A< string > as;
3.a关于形参,模板形参在其作用域中会屏蔽掉全局参数。
b形参的名字不能在模板内部重用,也就是说一个名字在一个模板中只能使用一次:
template<class u, class u> //error
c模板的声明和定义中参数的名字可以不同如:声明:template<class U> class A定义:template<class T> class A{}。
4.在模板内部指定类型
先看代码:template<class Parm, class d> parm fcn(parm *p, d value)
{Parm::size_type * p; //if Parm::size_type is a type, then it is a declaration
//if Parm::size_type is an object ,then multipication
}
如果要声名为类型,{}内应为 typename Parm::size_type *p;这种情况下fcn必须有size_type的成员,而且些成员为一类型。
5.非类型模板形参
个人认为就是在定义模板时指明了类型
6.模板代码的实例化
类模板在引用实际类型模板类时进行实例化,函数模板在调用它或用来对函数指针进行初始化或赋值时实例化。
类模板必须显示指明实参:Queue<int> q;在函数模板调用中,实参类型必须匹配,
7类型形参的实参的受限转换
A const 转换:不管传入的是不是const类型给接受非引用类型的函数,实参复制传入。采用相同的实例化。
B 如果模板形参不是const 型的,传入数组和函数会当成传入指针来处理。
例子:template <typename T> T fobj(T,T);
template <typename T> T fref(const T&, const T&);
string s1 ("is a string");
const string s2 ("another string");
fobj(s1,s2); //oK
fref(s1,s2); //OK s1 convert to const
int a[10],b[33];
fobj(a,b); //OK call fobj(int*,int*)
fref(a,b); //error can not convert to pointers
8函数模板的显式实参
A 指定显式模板实参
template<typename T,typename U> ? sum(T,U) ?处应用较大值者但T U在编写时无法确定谁大谁小
显式的用法 为 int i,short s;
sum(static_cast<int>(s),i);
B 在返回类型中使用类型形参
template <typename t1,typename t2,typename t3>
t1 func(t2,t3)
此例子中增加了一个t1用来定义返回类型,但是在调用中不会出现匹配t1的实参,这时需要显式的给出;
long val = func<long> (t2,t3);
需要注意的是显式模板实参从左向右依次与形参表中的形参相匹配,如果书写时没有注意顺序会出现错误:
template <typename t1,typename t2,typename t3>
t3 func(t1,t2)
long val = func<long> (t1,t2); //long ref to t1 so error
long val = func<long , int ,long> (t1,t2);//OK
在需要指明具体类型的地方都可用显式的声明,如在函数指针中。