函数模板
template<typename T> 函数声明或者定义作用:将类型参数化
#include<iostream>using namespace std;//交换两个整形voidswapint(int&a,int&b){int temp=a;a=b;b=temp;}//交换两个浮点型voidswapdouble(double&a,double&b){double temp=a;a=b;b=temp;}//函数模板template<typenameT>//声明一个模板,告诉编译器后面代码中紧跟的T不要报错,T是一个通用的数据类型voidmyswap(T&a,T&b){Ttemp=a;a=b;b=temp;}voidtest01(){int a=10;int b=20;//swapint(a, b);//利用函数模板交换//两种方式//1.自动类型推导//myswap(a, b);//2,显示指定类型myswap<int>(a,b);cout<<"a="<<a<<endl;cout<<"b="<<b<<endl;double c=1.1;double d=2.2;swapdouble(c,d);//cout << "c=" << c << endl;//cout << "d=" << d << endl;}intmain(){test01();system("pause");}函数模板注意事项
1.自动类型推导必须推导出一致的数据类型T才可以使用
2.模板必须要确定出T的数据类型才可以使用
#include<iostream>using namespace std;//实现通用 对数组进行排序的函数//从大到小 选择排序 char 数组 int数组template<classT>voidmyswap(T&a,T&b){Ttemp=a;a=b;b=temp;}template<classT>voidmysort(Tarr[],int len){for(int i=0;i<len;i++){int max=i;for(int j=i+1;j<len;j++){if(arr[max]<arr[j]){max=j;}}if(max!=i){myswap(arr[max],arr[i]);}}}template<classT>voidprintarray(Tarr[],int len){for(int i=0;i<len;i++){cout<<arr[i]<<" ";}cout<<endl;}voidtest01(){char chararr[]="ascbdf";int num=sizeof(chararr)/sizeof(char);mysort(chararr,num);printarray(chararr,num);}voidtest02(){int intarr[]={7,4,5,8,2,1};int num=sizeof(intarr)/sizeof(int);mysort(intarr,num);printarray(intarr,num);}intmain(){test02();system("pause");}普通函数和函数模板的区别
1.普通函数调用可以发生隐式类型转换
2.函数模板 用自动类型推导,不可以发生隐式类型转换
3.函数模板 用显式指定类型,可以发生隐式类型转换
#include<iostream>using namespace std;//普通函数intmyadd(int a,int b){returna+b;}//函数模板template<classT>Tmyadd1(Ta,Tb){returna+b;}voidtest01(){int a=10;int b=20;char c='c';cout<<myadd(a,c)<<endl;//输出109,此时c发生隐式类型转换cout<<myadd1(a,b)<<endl;//自动推导,不会发生隐式类型转换cout<<myadd1<int>(a,c);//显式指定类型会发生隐式类型转换}intmain(){test01();system("pause");}建议使用显式指定类型
普通函数和函数模板的调用规则
1.如果函数模板和普通函数都可以调用,优先调用普通函数
2.可以通过空模板函数列表的方式强制调用函数模板
3.函数模板也可以发生函数重载
4.如果函数模板可以发生更好的匹配,优先调用函数模板
#include<iostream>using namespace std;voidmyprint(int a,int b){cout<<"普通函数的调用"<<endl;}template<classT>voidmyprint(Ta,Tb){cout<<"模板的调用"<<endl;}template<classT>voidmyprint(Ta,Tb,Tc){cout<<"模板的调用"<<endl;}voidtest01(){int a=10;int b=20;myprint(a,b);//通过空模板的参数列表,强制调用函数模板myprint<>(a,b);myprint(a,b,100);char m='a';char n='b';myprint(m,n);}intmain(){test01();system("pause");}模板的局限性
模板不是万能的,有些特定的数据类型,需要用具体化方式做特殊实现
#include<iostream>using namespace std;#include<string>classperson{public:person(string name,int age){m_name=name;m_age=age;}string m_name;int m_age;};template<classT>boolmycompare(Ta,Tb){if(a==b){returntrue;}else{returnfalse;}}//利用具体化person版本template<>boolmycompare(person p1,person p2){if(p1.m_name==p2.m_name&&p1.m_age==p2.m_age){returntrue;}else{returnfalse;}}voidtest01(){int a=10;int b=20;//bool ret = mycompare(a, b);//if (ret) {// cout << "a=b" << endl;//}//else {// cout << "a!=b" << endl;//}personp1("TOM",10);personp2("TOM",10);bool ret=mycompare(p1,p2);if(ret){cout<<"p1=p2"<<endl;}else{cout<<"p1!=p2"<<endl;}}intmain(){test01();system("pause");}总结:
1.利用具体化模板,可以解决自定义类型的通用化
2.学习模板不是为了写模板,而是在STL能够运用系统提供的模板
文章总结:C++函数模板全面解析
一、核心概念
函数模板是C++泛型编程的基础,通过template<typename T>或template<class T>声明,将数据类型参数化,实现代码复用。
二、主要内容要点
1. 函数模板基础
- 语法:
template<typename T> void func(T param) - 作用:将类型参数化,避免为不同类型编写重复代码
- 使用方式:
- 自动类型推导:
func(a, b) - 显式指定类型:
func<int>(a, b)
- 自动类型推导:
2. 注意事项
- 自动类型推导必须推导出一致的数据类型T
- 模板必须确定出T的数据类型才能使用
3. 普通函数与函数模板的区别
| 特性 | 普通函数 | 函数模板 |
|---|---|---|
| 隐式类型转换 | 支持 | 自动推导不支持,显式指定支持 |
| 代码复用性 | 低 | 高 |
| 编译时处理 | 编译时确定 | 编译时实例化 |
4. 调用规则(优先级)
- 优先调用普通函数:如果两者都可调用
- 强制调用模板:通过空模板参数列表
func<>() - 模板重载:函数模板支持重载
- 模板优先:如果模板能更好匹配参数类型
5. 模板的局限性
- 不是万能的:某些特定数据类型需要特殊处理
- 解决方案:使用具体化模板(template specialization)
- 应用场景:自定义类型(如类对象)的比较操作
- 核心思想:学习模板是为了运用STL等系统提供的模板
三、关键代码示例
- 基本模板:
template<typename T> void swap(T& a, T& b) - 数组排序模板:支持不同类型数组的通用排序
- 类型转换对比:展示普通函数与模板在隐式转换上的差异
- 具体化模板:为自定义Person类实现特殊比较逻辑
四、学习建议
- 掌握基础语法:理解
template关键字和类型参数 - 区分使用场景:知道何时用普通函数,何时用模板
- 理解编译机制:模板是在编译时实例化的
- 实践应用:重点学习如何在STL中运用系统模板
- 注意局限性:了解模板的边界,学会使用具体化解决特殊需求
五、总结
函数模板是C++泛型编程的核心工具,通过类型参数化实现代码的高度复用。虽然功能强大,但也有其局限性,需要结合具体化模板等技术来解决特殊问题。最终目标是能够熟练运用STL等库中提供的成熟模板,提高开发效率。
核心价值:一次编写,多处使用;类型安全,编译时检查;提高代码复用性和可维护性。