首页 > 编程知识 正文

模板函数和函数模板的区别,类模板函数怎么调用

时间:2023-05-03 08:14:01 阅读:25134 作者:2919

泛型编程

一、函数模板

函数模板适用于功能相似的函数,如果函数参数相同,函数名称相同。1、函数模板的定义

模板类型参数列表//模板标题返回值类型函数名称(函数类型参数列表)函数体; }示例: templatetypenameTTadd(ta,T b ) {return a b; } 2、类型形参列表

例如,typename T1、typename T2说明: typename用于声明类型。 T1、T2是类型参数,可以是函数的返回值类型、类型参数类型、局部变量类型。3、函数模板的使用

使用模板也称为模板实例化,在调用函数模板时,必须将类型实参数传递到模板标头的类型参数列表中。 1 )常用用法)函数名称类型实参列表(数据实参列表); 示例:定义函数模板: templatetypenameTTadd(ta,T b ) {return a b; }使用函数模板: intc=addint (1,2 ); //在调用函数模板时给出类型实参cout c endl;

2 )函数模板类型参数的默认值在声明函数模板时可以指定类型参数的默认值。 示例:定义具有类型参数默认值的函数模板templatetypenamet=inttadd(ta,T b ) {return a b; }使用具有默认类型参数的函数模板intc=add (1,2 ); //型参数的默认值,不需要给出型实参数,但不能省略cout c endl;

3 )类型参数的自动推导addint (1,3 )===add ) 1,3 ); //自变量1,3明显是整数型,所以可以自动导出得到型自变量。

4、函数模板的特化定义

特化定义是用于解决特定类型作为类型参数的函数模板的定义问题,是函数模板通用定义的补充。 函数模板的常规定义面向int、char和string等常规类型作为类型参数,因此如果需要使用复杂类型、指针类型和引用类型(如const char * )作为函数模板的类型参数,则无法解决此问题函数模板的特殊定义: template返回类型函数名称类型实际参数列表(数据格式参数列表)函数体; }**全局函数、函数模板的公共定义、函数模板的专用定义**1)调用顺序:函数模板的专用定义(其中函数优先于函数模板)被调用,优先于函数模板的公共定义。 2 )全局函数与函数模板之间构成了重载关系

二、类模板

函数模板和类模板有两个需要区分的地方。 1 )函数模板具有自动类型派生,类模板中没有。 2 )类模板有特化定义和偏特化定义之分; 另一方面,函数模板只有特化定义,没有特化定义。1、类模板的定义

template typname T1,typename T2 //类模板模板标题class Demo{public:定义公共成员; private:私人成员定义; (;2、类模板的使用

1、常用用法:类名类型实参列表对象名称2、类型参数默认值:1)定义类模板时,可以指定类型参数的默认值。 模板类型名称t1,类型名称T2=intclassdemo {公共:公共成员定义; private:私人成员定义; }2)调用具有类型参数默认值的类模板时,调用类型实参数示例(Demostring,int demo1===Demostring demo1; 3 )类型参数自动推导)类模板不支持类型自动推导,必须指定类型。 即使指定了类型参数的默认值,也不能省略“”。 用户命名空间STD; #include iostream//定义具有形状参数默认值的函数模板template typename T1,typename T2=stringclassdemo { public 3360 demo (t1a,T1 b }int compare () {int ret=0; if(a!=b ) ret=a b? 1:0; 返回ret; }隐私: t a; 丁乙; (; int main () {Demoint,int demo1(1,3 ); //实例化函数模板demo.show(666

);cout << d.compare() << endl;Demo<int> demo2(1,2);//调用类型形参默认值的类模板 demo2.show(string("Hello World"));//Demo d3(1,2);//error类模板不支持自动类型推导 //Demo<> demo4(1,2);//假设类型形参全部指定了默认值,<>也不可以省略。return 0;} 例题:在类的通用模板中对成员函数做声明,在类外部进行定义。 using namespace std;#include <iostream>template <typename T>class Demo{public:void show();private:T val;};//类模板中成员函数的定义 template <typename T>void Demo<T>::show(){cout << "show()一下" << endl;}int main(){Demo<int> demo1;demo1.show();return 0;}

3、类模板的全特化定义

与函数模板的全特化定义类似,类模板的全特化定义时针对特殊的类型的定义,是对通用定义的补充。类模板的全特化定义:template<>class Demo<类型实参列表>{public:公有成员;private:私有成员;}; 例如:template <>class Demo<const char*, int>{public:公有成员;private:私有成员;}

注意

在一个源文件中不能只有模板的全特化定义或者偏特化定义,必须还有模板的通用定义,否则源程序无法正常编译。因为特化定义和偏特化定义本来就是对通用定义的补充,如果没有通用定义则特化定义和偏特化定义则不合法。 例题:1、错误示范,只有特化定义,没有通用定义:using namespace std;#include <iostream>//类模板的特化定义template<>class Compare<float>{public:bool equal(float a, float b);//在类模板的内部对成员函数进行声明 };//在类模板的外部对成员函数进行定义 bool Compare<float>::equal(float a, float b){return a == b;}int main(){Compare<flaot> c1;cout << c1.equal(1.01, 1.02) << endl;return 0;}//运行结果:编译出错误,无法通过。编译器检查到Compare不是一个类模板 2、正确示范:在特化定义的前面先进行通用的定义。using namespace std;#include <iostream>//类模板的通用定义 template<typename T>class Compare{public:bool equal(T a, T b);//类模板的内部进行成员函数的声明};//在类模板的外边进行定义 template <typename T>bool Compare<T>::equal(T a, T b){return a == b;}//类模板的特化定义template<>class Compare<float>{public:bool equal(float a, float b);//在类模板的内部对成员函数进行声明 };//在类模板的外部对成员函数进行定义 bool Compare<float>::equal(float a, float b){return a == b;}int main(){Compare<flaot> c1;cout << c1.equal(1.01, 1.02) << endl;return 0;}//运行结果:结果正确,符合预期结果。

4、类模板的偏特化定义

如果类模板有多个类型参数,进行特化定义是只需要特化部分类型参数,则成为偏特化定义。如果需要特化全部的类型参数就称为全特化定义。类模板的偏特化定义形式:template <typename T>class 类名<特化类型,T>{public:公有成员;private:私有成员;}; template <typename T>class Demo<const char*, T>{public:公有成员;private:私有成员;}; 模板调用时的匹配规则:1)全特化类模板优先于偏特化类模板2)偏特化类模板优先于通用类模板

三、pair<T1, T2>类模板

1)标准库中的pair是一个类模板,需要包含头文件<utility>。2)pair可以将任意类型的两个数据组合成一个数据对。3)pair包含两个公有的数据成员first和secondpair<T1, T2>的用法:1)pair<T1, T2> p1;调用无参构造函数定义一个空的pair对象,pair对象的两个成员变量的类型分别是T1和T2,没有值。2)pair<T1, T2> p2(v1, v2);调用有参构造函数,定义了一个pair对象,first成员变量的类型为T1,值为v1;second成员变量的类型是T2,值为v2。3)p1 == p2如果p1和p2的两个数据成员变量first和second都相等则p1与p2相等。4)p1 < p2遵循字典次序:第一种情况,p1.first < p2.first;第二种情况,p1.first = p2.first 且p1.second < p2.second 例1:利用运算符的重载,使其可以输出pair类对象 using namespace std;#include <iostream>#include <utility>//运算符重载函数 ostream& operator<<(ostream& out, pair<int, string>& p){out << "p.first:" << p.first << endl;out << "p.second:" << p.second;return out;}int main(){pair<int, string> p(1001, string("lilei"));cout << p << endl;return 0;} 例2:在上述例题的基础上使用函数模板,使输出运算符可以输出多种类型的pair对象 using namespace std;#include <iostream>#include <utility>template <typename T1, typename T2>ostream& operator<<(ostream& out, const pair<T1, T2>& p){out << "p.first:" << p.first << endl;out << "p.second:" << p.second;reutrn out;}int main(){pair<int, int> p1(1,3);cout << p1 << endl;pair<int, string> p2(1001, string("lilei"));cout << p2 << endl;return 0;}

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。