C++模板之函数模板实例化和具体化
模板声明 template<typename/class T>, typename比class最近后添加到C++标准。
常规模板,具体化模板,非模板函数的优先调用顺序。
非模板函数(普通函数)> 具体化模板函数 > 常规模板
显示具体化:
具体化表示为某一特定的类型重写函数模板,声明的含义是使用独立的,专门的函数定义显示地为 特定类型生成函数定义。
为什么要有显示具体化?处理模板函数所不能处理的特殊情况。显式具体化显式具体化也是基于函数模板的,只不过在函数模板的基础上,添加一个专门针对特定类型的、实现方式不同的具体化函数。
显示具体化声明在关键字template后包含<>.
如:
- template<> void swap<job>(job &j1, job &j2);
vs2013不支持:
- void swap(Any &a, Any &b);
- struct job
- {
- char name[40];
- double salary;
- int floor;
- };
- template<> void swap<job>(job &j1, job &j2);
- void Show(job &j);
- int main(){
- using namespace std;
- template void swap<job>(job &, job &);
- int i = 10, j = 20;
- swap(i, j);
- return 0;
- }
- template<typename Any>
- void swap(Any &a, Any &b){
- Any temp;
- temp = a;
- a = b;
- b = temp;
- }
- template<> void swap<job>(job &j1, job &j2){
- double temp_sal;
- temp_sal = j1.salary;
- j1.salary = j2.salary;
- j2.salary = temp_sal;
- }
隐式实例化
在发生函数模板的调用时,不显示给出模板参数而经过参数推演,称之为函数模板的隐式模板实参调用(隐式调用)。如:
1 2 3 4 5 | template <typename T> void func(T t) { cout<<t<<endl; } func(5); //隐式模板实参调用 |
显示实例化:
实例:如函数调用swap(i,j)会导致编译器生成swap()的一个实例,该实例使用 int 类型。
句法:声明所需的种类用<>符号指示类型,并在声明前加上关键字template:
为什么要有显示实例化?事实上,编译器只在要调用函数的时候才使用到函数,如果不使用显示实例化,每次调用函数时,模板都会消耗性能去推导使用的是哪个类型的函数,增加了程序运行时的负担;使用了显示实例化,则在编译时就已经处理了函数选择。
- template [函数返回类型] [函数模板名]<实际类型列表>(函数参数列表)
实例化示例:
- template void swap<int>(int, int);
注意:试图在同一个文件(或转换单元)中使用同一种类型的显示实例化和显示具体化声明,会出错。
推荐:可以用在函数调用时,直接显示实例化,而不使用显示实例化声明。
如:
1 2 3 4 5 6 7 8 9 10 11 12 | template < typename T> T add(T x,T y) { return x+y; } int main() { int i1=2,i2=3; add< int >(i1,i2); template int add< int >(i1,i2); //尽量用上面一行的写法代替本行 return 0; } |
模范代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | ///********************************************** /// @file templetAdd.cc /// @author alex(AlexCthon@qq.com) /// @date 2018-06-19 21:42:20 ///**********************************************/ #include <string.h> #include <iostream> using std::cout; using std::endl; //模板-->类型参数化-->代码生成器 // 实例化(模板参数推导) //函数模板 --> 模板函数 //< > 模板参数列表 //1、使用class 或者typename设置类型参数 //2、非类型参数、常量表达式(整型数据) template < class T> T add(T x,T y) { return x + y; } #if 0 template int add< int >( int x, int y) // { cout<< "template 显示实例化" <<endl; return x+y; } #endif template <> int add< int >( int x, int y) //等价于template<>int add(int x,int y) { cout<< "template 显示具体化" <<endl; return x+y; } //模板的特化版本,不能独立用于通用版本 //针对特殊情形,但一定要在通用版本存在时才能用 template <> //把这行注释掉也是可以的,那表明下面的这个方法是重载了模板函数 const char * add( const char *lhs, const char * rhs) { char *tmp = new char [ strlen (lhs)+ strlen (rhs)+1](); strcpy (tmp,lhs); strcat (tmp,rhs); return tmp; } #if 0 //普通函数与函数模板可以重载 //普通函数优先级高于模板函数 int add( int x, int y) //可以重载,因为形参类型不一样 { return x + y; } #endif //函数模板与函数模板之间也可以重载 //函数模板的声明 template < typename T> T add(T x,T y,T z); //c++11的特性 //c++11以前的版本对于函数模板而言,非类型参数不能设置默认值 //非类型参数必须是整形类数据(bool、char、int、long、long long) template < typename T, int num=10> int func(T x,T y) { return x*y*num; } int main() { int a=3,b=4; double c1=1.2,c2=2.3,c3=4.9; char ch1= 'a' ,ch2=2; //template char add<char>(char x,char y);//试图在同一个文件(或转换单元)中使用同一种类型的显示实例化和显示具体化声明,会出错 func(ch1,ch2); const char *p1= "hello" ; const char *p2= "good" ; cout << "int + int = " << add(a,b) << endl; //隐式实例化 cout << "double + double = " << add< int >(c1,c2) << endl; //显示实例化 cout << "char + char = " << add(ch1,ch2) << endl; cout << "double + double = " << add(c1,c2,c3) << endl; cout << "int + int = " << func< double ,8>(a,b) << endl; //常量传递的方式 //cout << "a+d1=" << add(a,c1) << endl;//error,模板参数必须严格一致 cout << add(p1,p2) << endl; return 0; } //函数模板的实现 template < class T> T add(T x,T y,T z) { return x +y + z; } |
总结:
隐式实例化指的是:在使用模板之前,编译器不生成模板的声明和定义实例。只有当使用模板时,编译器才根据模板定义生成相应类型的实例。如:int i=0, j=1;swap(i, j); //编译器根据参数i,j的类型隐式地生成swap<int>(int &a, int &b)的函数定义。Array<int> arVal;//编译器根据类型参数隐式地生成Array<int>类声明和类函数定义。
显式实例化:当显式实例化模板时,在使用模板之前,编译器根据显式实例化指定的类型生成模板实例。如前面显示实例化(explicit instantiation)模板函数和模板类。其格式为:template typename function<typename>(argulist);template class classname<typename>;显式实例化只需声明,不需要重新定义。编译器根据模板实现实例声明和实例定义。
显示具体化:对于某些特殊类型,可能不适合模板实现,需要重新定义实现,此时可以使用显示具体化(explicite specialization)。显示实例化需重新定义。格式为:template<> typename function<typename>(argu_list){...};template<> class classname<typename>{...};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现