一、为什么使用函数模板

假设我们在程序中需要比较两个变量的大小,但变量的类型可能是int、float或者double,此时为了满足程序的要求我们可能会在程序中编写多个函数,如:

 //比较两个int型变量的大小
int compare(const int &a,const int &b){
return a>b?a:b;
}
//比较两个float型变量的大小
float compare(const float &a,const float &b){
return a>b?a:b;
}
//比较两个double型变量的大小
double compare(const double &a,const double &b){
return a>b?a:b;
}

在上面的代码中,我们发现编写的函数除了函数参数类型和返回值类型不同之外其余完全相同,这样导致的结果就是该程序代码的冗余性较高。为了解决这个问题,我们可以使用函数模板来编写与类型无关的函数以降低程序的冗余性

二、什么是函数模板

一个函数模板就是一个公式,可用来生成针对特定类型的函数体

语法:

template <typename 形参名,typename 形参名,......>
返回值类型 函数名(参数列表){
/*..........
函数体
...........*/
}

实例演示:

 //compare函数的函数模板
template <typename type>
type compare(const type &a,const type &b){
return a>b?a:b;
}

 特别注意:

1.在函数模板的定义中,模板参数列表不能为空

2.在进行模板定义的时候可以用关键字class代替关键字typename,二者在这里是等价的。甚至可以在定义函数模板时同时使用这两个关键字,但还是推荐使用typename,因为这样会使程序的可读性更好

 template <typename type1,class type2>
void func(type1 a,type2 b){
cout<<a<<endl;
cout<<b<<endl;
}

3.模板参数(<>包裹的参数)表示在函数定义中使用到的类型或值。当使用模板时,我们(隐式地或显式地)指定模板实参,将其绑定到模板参数上

4.inline和constexpr的函数模板:将关键字inline或constexpr放在模板参数之后,返回值类型之前即可

 //inline函数的函数模板
template <typename type>
inline type func(type a){
a+=;
return a;
}

三、函数模板的实例化

当我们调用一个函数模板时,编译器(通常)用函数实参来为我们推断模板实参,例如上面的compare函数,编译器会使用函数实参的类型来确定模板参数type的类型。

特别注意:

1.编译器会用推断出的模板参数来为我们实例化一个特定版本的函数,换句话说就是编译器会使用实际的模板实参来替代对应的模板参数来创建出一个模板的新“实例”

 template <typename type>
type compare(const type &a,const type &b){
return a>b?a:b;
} int main(){
//实例化为 int compare(const int&,const int&)
cout<<compare(,)<<endl;
//实例化为float compare(const float&,const float&)
cout<<compare(1.2f,2.3f)<<end;
//实例化为double compare(const double&,const double&)
cout<<compare(1.2,2.3)<<endl;
return ;
}

2.当编译器遇到一个模板定义时,它并不生成代码。只有当我们实例化出模板的一个特定版本时,编译器才会生成代码。

3.为了生成一个实例化的版本,编译器需要掌握函数模板的定义,因此与非模板代码不同,模板的头文件通常既包括声明也包括定义

四、函数模板的形参


A、类型形参:类型形参由关见字class或typename后接说明符构成,如:

 template <typename type> //类型形参
void func(type a){
......
}

特别注意:

1.我们可以将类型参数看做类型说明符,就像内置类型或类类型说明符一样使用。

2.不能在函数调用的参数中指定模板形参的类型,对函数模板的调用应使用实参推演来进行,也就是说不能以func(int)的形式调用上面的函数模板func,只能以func(1)的形式调用。


B、非类型形参:非类型形参的参数表示一个值而非一个类型,通常情况下,我们通过一个特定的类型名而非关键字typename或class来指定非类型形参。

特别注意:

1.当一个模板被实例化时,非类型形参会被一个用户提供的或编译器推断出的值所替代,这些值必须是常量

 template <unsigned N,unsigned M>
int compare(const char (&p1)[N],const char (&p2)[M]){ //p1和p2是对数组的引用,而N和M都表示数组的长度
return strcpy(p1,p2);
}

当我们调用这个版本的compare函数时“

compare("Tomwenxing","Jack");

编译器会用字面值常量的大小来代替N和M,从而将模板实例化。另外编译器会在字符串字面常量的末尾插入一个空字符作为终结符,因而编译器最终实例化出的版本如下:

int compare(const char (&p1)[],const char (&p2)[])

2.一个非类型形参可以是一个整型,也可以是一个指向对象或函数类型的指针或引用。其中绑定到非类型整型参数的实参必须是一个常量表达式而绑定到指针或引用非类型参数的实参必须具有静态的生存期

 3.函数模板中需要常量表达式的地方(比如说数组的大小),可以使用非类型形参

C++:模板——函数模板1的更多相关文章

  1. C++学习笔记35:函数模板

    函数模板 函数模板的目的 设计通用的函数,以适应广泛的数据型式 函数模板的定义格式 template<模板型式参数列表>返回值型式 函数名称(参数列表): 原型:template<c ...

  2. C++ template学习一(函数模板和模板函数)

    函数模板和模板函数(1)函数模板函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计.它的最大特点是把函数使用的数据类型作为参数.函数模板的声明形式为:templat ...

  3. 关于C++编译链接和模板函数

    一,关于编译链接编译指的的把编译单元生成目标文件的过程链接是把目标文件链接到一起的过程编译单元:可以认为是一个.c或者.cpp文件.每个编译单元经过预处理会得到一个临时的编译单元.预处理会间接包含其他 ...

  4. 25.C++- 泛型编程之函数模板(详解)

    本章学习: 1)初探函数模板 2)深入理解函数模板 3)多参函数模板 4)重载函数和函数模板 当我们想写个Swap()交换函数时,通常这样写: void Swap(int& a, int&am ...

  5. C++—模板(1)模板与函数模板

    1.引入 如何编写一个通用加法函数?第一个方法是使用函数重载, 针对每个所需相同行为的不同类型重新实现这个函数.C++的这种编程机制给编程者极大的方便,不需要为功能相似.参数不同的函数选用不同的函数名 ...

  6. C++解析(26):函数模板与类模板

    0.目录 1.函数模板 1.1 函数模板与泛型编程 1.2 多参数函数模板 1.3 函数重载遇上函数模板 2.类模板 2.1 类模板 2.2 多参数类模板与特化 2.3 特化的深度分析 3.小结 1. ...

  7. c++之旅:函数模板

    函数模板 函数模板主要是泛型在函数的中的应用,通过泛型可以让函数处理各种各样的数据类型 简单的列子 #include <iostream> using namespace std; tem ...

  8. C++模板之函数模板实例化和具体化

    模板声明 template<typename/class T>,  typename比class最近后添加到C++标准. 常规模板,具体化模板,非模板函数的优先调用顺序. 非模板函数(普通 ...

  9. C++ 函数模板与类模板(使用 Qt 开发编译环境)

    注意:本文中代码均使用 Qt 开发编译环境,如有疑问和建议欢迎随时留言. 模板是 C++ 支持参数化程序设计的工具,通过它可以实现参数多态性.所谓参数多态性,就是将程序所处理的对象的类型参数化,使得一 ...

随机推荐

  1. 求助:将以下ES5格式代码转换为ES6格式!!!

    function Slider(id){     //属性     //  1. 通过id获取元素对象(大盒子)     this.bigBox = document.getElementById(i ...

  2. 利用canvas将网页元素生成图片并保存在本地

    利用canvas将网页元素生成图片并保存在本地 首先引入三个文件: 1.<script type="text/javascript" src="js/html2ca ...

  3. 记一次Apache Carbondata PR的经历

     前言 前段时间有幸接触到Apache Carbondata,试用过程中发现了一个小小的问题,并且又很快的定位到了问题.然后在社区群里反映了下,负责人问愿不愿意提个JIRA,PR,然后我在没有任何开源 ...

  4. iOS Swift WisdomKeyboardKing 键盘智能管家SDK

    iOS Swift WisdomKeyboardKing 键盘智能管家SDK [1]前言:    今天给大家推荐个好用的开源框架:WisdomKeyboardKing,方面iOS日常开发,优点和功能请 ...

  5. Linux下开发python django程序(Session读写)

    1.登陆设置session信息 def loginsession(req): if req.method == 'POST': loginform = LoginForm(req.POST) if l ...

  6. OpenStack入门篇(二十二)之实现阿里云VPC的SDN网络

    1.修改/etc/neutron/neutron.conf配置 [root@linux-node1 ~]# vim /etc/neutron/neutron.conf [defalut] ... co ...

  7. TMS320VC5509启动模式选择

    1. TMS320VC5509内部没有存储空间,所以需要外部接flash.如果使用JTAG仿真板子的话,应该是选择USB下载模式,同时EEPROM应该是支持SPI FALSH的.

  8. 2_C语言中的数据类型 (四)整数与无符号数

    1.1       sizeof关键字 sizeof是c语言关键字,功能是求指定数据类型在内存中的大小,单位:字节 sizeof与size_t类型 1.1       int类型 1.1.1      ...

  9. 通过IDEA解决spring配置文件

    来自:https://blog.csdn.net/yanghanxiu/article/details/79366263 (其实尼可以使用springboot 这样就不用配置一大堆东西了喵!) 每次创 ...

  10. 细说 Django — web 前后端分离

    一.所谓的前后端分离 1.渊源 前端发展史 2.特点 前端:负责 View 和 Controller 层 后端:只负责 Model 层,业务处理/数据等 3.优缺点 优点:解耦,解放前端,职责明确 缺 ...