泛型编程就是以独立于任何特定类型的方式编写代码。它也是一种多态的应用,它可以使一个类或者一个函数操纵不同类型的对象。模板是泛型编程的接触。下面是个人对模板学习的一点总结。
1.函数模板
函数模板的定义以关键字template开始,后面接模板形参表,然后是函数返回类型,函数名称,函数形参表,函数体。例如:
template <class T,size_t N> void array_init(T (&parm)[N]) {
for (size i=0; i!=N; i++)
parm[i] = 0;
}
其中template后面<>内就是模板形参表,模板形参表里面可以是表示类型的类型形参,我们就知道形参里面表示未知类型,如T;也可以是表示常量表达式的非类型形参,我们知道形参里面是一个未知的值,如N。
函数模板在实例化的时候,是根据实参的类型通过推断的方式,实例化相应类型的模板函数。
这里面有几点注意的地方
1)函数模板有多个类型的形参时,所传递的多个类型的实参类型必须完全匹配
例如:
template <class Type> int compare(const Type&m, const Type&n){........}
short s1;
int s2;
compare(s1,s2);
此时会出错,因为s1和s2的类型不完全匹配。
2)涉及数组的问题。
当模板形参不是引用的时候,数组会转换为指针类型,但是当其为引用的时候,此时不仅数组的类型要相同,数组长度也会起作用。当不是引用的时候,数组名会转化为相应的指针。
例如:
template <class T> void fun(const T&, constT&);
template <class T> void fun1(T, T);
int a[10],b[20];
fun(a,b);//error
fun1(a,b);//ok,此时推断的T类型均为int *符合要求。
3)可以使用显式实参
通常的做法可以再函数模板形参中增加一个用于指定函数返回类型的形参,如
template<classT1,classT2,classT3>
T1 fun(T2,T3);
long i = fun<long>(2,5L);
long i = fun<long,int,long>(2,4L);
这里面显式制定了函数的返回类型T2的类型为long,上面两种方式均可以。注意类型的匹配顺序,显式指定的类型与
template<classT1,classT2,classT3>中定义三种类型的顺序一致。T1显式指定为返回类型T1,T2,T3可以用推断的方式匹配。
2.类模板
template+<模板形参>+class 类名 {
类体
};
注意在使用类模板名字的时候,如果在类体外一定把模板形参的具体类型带上,比如vector<int>,这个int 一定不能忘记,因为单独的vector是无效的。但是在类体内,一般都要用到类模板的名字,因为构造函数之类的函数名就是类名,但在类体内可以放宽条件,不必带上模板形参的具体类型。如果在类体内使用其他类模板,是要指定模板形参的。
类模板的成员函数在类体外定义时采用的格式为:
template <class T> return_type Class_template_name<T>::member_name();
3.类模板中的友元声明
1)声明的友元为非类模板、非函数模板
friend class aaa1;
friend void fun1();
这样就可以,正常。
2)声明的友元为一般模板
template<class T> friend class FOO1;
template<class T> friend void fun2(const T&);
3)声明友元为特定的模板
可以对模板的特定实例授予友元关系,记得前面要给出声明
template<class T> friend class G;
template<calss T> friend void fun(const T&);
template<class Type> class M {
public:
friend class G<int>;
friend class fun<string>(const string&);
}