【C++】模板简述(二):函数模板
我们上文讲了,模板的引入,我们发现在某种特殊的情况下,必须得通过模板才能完美的解决问题.
本文就来简述一下函数模板的基本使用.
一、函数模板格式
- template<typename Param1, typename Param2,...,class Paramn>
- 返回值类型 函数名(参数列表){
- ...
- }
二、函数模板的实例
- //T表示类型,具体是什么不知道,实例化的时候才知道
- //typename可以用class代替,但推荐使用typename
- //注意:typename不能用struct代替!!!
- template<typename T>
- T Add(const T l,const T r){
- return l+r;
- }
- //模板函数也可以定义为inline
- //注意inline的位置,必须在template之后,返回值之前
- template<typename T>
- inline T Add(const T l,const T r){
- return l+r;
- }
注意:模板本身并不是函数或类,它只是一个泛型的代码.
编译器在通过模板来生成特定类型的代码这一过程称之为:模板的实例化.
因此,模板被编译了两次:
第一次编译在实例化之前,编译时完成的工作主要是:检查模板代码本身是否有语法问题(比如少个分号什么的)
第二次编译时在实例化期间,再次检查模板代码,在特定类型下,所有的调用是否都有效.
三、函数模板的形参
首先,模板有两种参数,类型形参与非类型形参.
- //T为类型形参,N为非类型形参
- template<typename T,int N>
- T Add(const T l,const T r){
- return l+r;
- }
模板形参小结:
1.模板形参名字只能在模板形参之后到模板声明或定义的末尾之间使用,遵循名字屏蔽规则.
2.模板形参的名字在同一模板形参列表中只能使用一次.
3.所有类型形参前面必须加上class或者typename关键字修饰.
4.函数模板的内部不能指定缺省参数.
四、模板函数的重载
- template<typename T>
- int Add(const int a,const int b){
- return a+b;
- }
- T Add(const T l,const T r){
- return l+r;
- }
- template<typename T>
- T Add(const T a,const T b,const T c){
- return a+b+c;
- }
- template<typename T1,typename T2>
- T1 Add(const T1 l,const T2 r){
- return l+r;
- }
- template<typename T,int N>
- void Print(const T (&arr)[N]){
- for(int i=0; i<N; ++i){
- cout<<arr[i]<<" ";
- }
- cout<<endl;
- }
- //...
- cout<<Add(1,2)<<endl; //int Add(const int,const int)
- cout<<Add<>(1,2)<<endl; //T Add(const T l,const T r)
- cout<<Add(1,2,3)<<endl; //T Add(const T a,const T b,const T c)
- cout<<Add(1,2.2)<<endl; //T1 Add(const T1 l,const T2 r)
- cout<<Add(1.1,2)<<endl; //T1 Add(const T1 l,const T2 r)
模板函数重载说明:
1.一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。
2.对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调动非模板函数而不会从该模板产生出一个实例.如果模板可以产生一个具有更好匹配的函数,那么将选择模板.
3.显式指定一个空的模板实参列表,该语法告诉编译器只有模板才能来匹配这个调用,而且所有的模板参数都应该根据实参演绎出来.
4.模板函数不允许自动类型转换,但普通函数可以进行自动类型转换.
五、模板函数的特化
在某些情况下,通用模板定义对于某个类型可能是完全错误的,或者不能编译,或者做一些错误的事情:
- template<typename T>
- T Max(const T l,const T r){
- return l>r?l:r;
- }
- //....
- char *str1="123456789";
- char *str2="abcdefhij";
- cout<<Max(1,2)<<endl; //正确
- cout<<Max(str1,str2)<<endl; //错误,它比较的是指针的大小,而不是ASCII码
因此,我们需要用到模板的特化:
- template<>
- const char* Max<const char*>(const char* l,const char* r){
- int ret = strcmp(l,r);
- return ret>0?l:r;
- }
注意:
1.在特化时如果少了形参列表,那么只是定义了一个普通的函数,该函数含有返回类型与模板实例化相匹配的形参表.
2.在模板特化版本的调用中,实参类型必须与特化版本函数的形参类型完全匹配,如果不匹配,编译器将为实参模板定义中实例化一个实例.
3.特化不能出现在模板实例的调用之后,应该在头文件中包含模板特化的声明,然后使用该特化版本的每个源文件包含该头文件.
五、模板函数的参数推演
从函数实参确定模板形参类型和值的过程称为模板实参推断.
类型形参转换时,一般不会转换实参以匹配已有的实例化,相反会产生新的实例.
而编译器只会执行两种转换:
1、const转换:接收const引用或者const指针的函数可以分别用非const对象的引用或者指针来调用
2、数组或函数到指针的转换:如果模板形参不是引用类型,则对数组或函数类型的实参应用常规指针转换.数组实参将当做指向其第一个元素的指针,函数实参当做指向函数类型的指针.
【C++】模板简述(二):函数模板的更多相关文章
- 【C++】模板简述(三):类模板
上文简述了C++模板中的函数模板的格式.实例.形参.重载.特化及参数推演,本文主要介绍类模板. 一.类模板格式 类模板也是C++中模板的一种,其格式如下: template<class 形参名1 ...
- C++ 函数模板一(函数模板定义)
//函数模板定义--数据类型做参数 #include<iostream> using namespace std; /* 函数模板声明 1.函数模板定义由模板说明和函数定义组成,并且一个模 ...
- C++模板学习:函数模板、结构体模板、类模板
C++模板:函数.结构体.类 模板实现 1.前言:(知道有模板这回事的童鞋请忽视) 普通函数.函数重载.模板函数 认识. //学过c的童鞋们一定都写过函数sum吧,当时是这样写的: int sum(i ...
- 【C++】模板简述(六):总结
1.模板技术是泛型编程的基础.([C++]模板简述(一):模板的引入) 2.模板被编译两次,因而给分离编译造成一些麻烦.([C++]模板简述(二):函数模板.[C++]模板简述(四):模板为什么不支持 ...
- C++学习笔记之模板(1)——从函数重载到函数模板
一.函数重载 因为函数重载比较容易理解,并且非常有助于我们理解函数模板的意义,所以这里我们先来用一个经典的例子展示为什么要使用函数重载,这比读文字定义有效的多. 现在我们编写一个交换两个int变量值得 ...
- C++_进阶之函数模板_类模板
C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...
- [转]C++函数模板与模板函数
1.函数模板的声明和模板函数的生成 1.1函数模板的声明 函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计.它的最大特点是把函数使用的数据类型作为参数. ...
- 019_linuxC++之_函数模板引入
(一)首先我们来看非模板程序,函数只是输入不一样的变量就需要构件很多个不一样的函数,那么这样很麻烦,则引入函数模板 int& max(int& a, int& b) { ret ...
- C++ 函数模板&类模板详解
在 C++ 中,模板分为函数模板和类模板两种.函数模板是用于生成函数的,类模板则是用于生成类的. 函数模板&模板函数 类模板&模板类 必须区分概念 函数模板是模板,模板函数时 ...
随机推荐
- 设置ArcGIS的数据源
我从别的地方拿到一份现成的地图文档(*.mxd),在该服务器上运行得好地地,图文并茂,但用我自己机器的arcMap打开就一片空白,啥都没有. 看左边的各个图层目录,图标上都有个粉红色的惊叹号,醒悟过来 ...
- myecplise、ecplise项目空间优化
1.代码自动提示补全 Window->preferences->Java->Editor->Content Assist 再右下角Auto activation trigger ...
- Hibernate 之 Locking
在我们业务实现的过程中,往往会有这样的需求:保证数据访问的排他性,也就是我正在访问的数据,别人不能够访问,或者不能对我的数据进行操作.面对这样的需求,就需要通过一种机制来保证这些数据在一定的操作过程中 ...
- FOUNDATION OF ASYNCHRONOUS PROGRAMMING
The async and await keywords are just a compiler feature. The compiler creates code by using the Tas ...
- Package vim is not available, but is referred to by another package及我的vim配置
新安装的ubuntu,先安装vim,但是安装出现 Reading package lists... Done Building dependency tree Reading state inform ...
- sphinx索引部分源码续——过程:连接到CSphSource对应的sql数据源,通过fetch row取其中一行,然后解析出field,分词,获得wordhit,最后再加入到CSphSource的Hits里
后面就是初始化一些存储结构,其中重点说下缓存出来的几个临时文件分别的作用.结尾时tmp0的存储的是被上锁的Index,有些Index正在被查询使用 故上锁.tmp1,即对应将来生成的spp文件,存储词 ...
- 并不对劲的p3709:大爷的字符串题
题目大意 区间众数 题解 莫队 代码 #include<algorithm> #include<cmath> #include<cstdio> #include&l ...
- 分拆数&&HDU4651
1,有两种DP,复杂度都是O(N^2),但是浪费的侧重点不同,所以根据侧重点分块DP,复杂度可以降到O(N^1.5). 2,母函数+五边形blabla... 占位. 其实就是母函数拆开后,快速知道哪些 ...
- 创建oracle数据库job服务
创建oracle数据库job服务:PlSqlDev操作job https://www.baidu.com/link?url=5vXhw0IqjvWEAgGSIYsSEVPvJb6njGkJ-_P_VF ...
- linux内存管理之全局框架
讲解复杂繁琐的机制原理,最通俗的方法就是用模型架构的方式向读者呈现,先要在整体上了解大方向大架构,再根据大方向大架构来进行分支深入,犹如毛主席那句话“战略上蔑视敌人,战术上重视敌人”.下面我也以这种方 ...