在《C++函数重载》一节中,为了求三个数的最大值,我们通过函数重载定义了三个名字相同、参数列表不同的函数,如下所示:

//求三个整数的最大值
int max(int a, int b, int c){
if(b>a) a=b;
if(c>a) a=c;
return a;
}
//求三个浮点数的最大值
double max(double a, double b, double c){
if(b>a) a=b;
if(c>a) a=c;
return a;
}
//求三个长整型数的最大值
long max(long a, long b, long c){
if(b>a) a=b;
if(c>a) a=c;
return a;
}

这些函数虽然在调用时方便了一些,但从本质上说还是定义了三个功能相同、函数体相同的函数,仍然不够节省代码。能不能把它们压缩成一个呢?

能!可以借助本节讲的函数模板。

我们知道,数据或数值可以通过函数参数传递,在函数定义时它们是未知的,只有在发生函数调用时才能确定其值。这就是数据的参数化。

其实,数据类型也可以通过参数来传递,在函数定义时可以不指明具体的数据类型,当发生函数调用时,编译器可以根据传入的参数自动确定数据类型。这就是数据类型参数化。

所谓函数模板,实际上是建立一个通用函数,其返回值类型和形参类型不具体指定,用一个虚拟的类型来代替(实际上是用一个标识符来占位)。这个通用函数就称为函数模板(Function Template)。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会用实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。

定义模板函数的语法为:

template <typename 数据类型参数 , typename 数据类型参数 , ...> 返回值类型 函数名(形参列表){
//TODO:
//在函数体中可以使用数据类型参数
}

其中,template 是定义模板函数的关键字,template后面的尖括号不能省略;typename 是声明数据类型参数名的关键字,多个数据类型参数以逗号分隔。例如,求两个数的值:

//在返回值类型、形参列表、函数体中都可以使用T
template<typename T> T sum(T a, T b){
T temp = a + b;
return temp;
}

template<typename T>为模板头,T为类型参数。模板函数的调用形式和普通函数一样:

int n = sum(, );
float m = sum(12.6, 23.9);

编译器可以根据调用时传递的参数来自动推演数据类型。

改进本节开头的代码,通过函数模板来求三个数的最大值。

#include <iostream>
using namespace std;
template<typename T> //模板头,这里不能有分号
T max(T a, T b, T c){ //函数头
if(b>a) a=b;
if(c>a) a=c;
return a;
}
int main( ){
//求三个整数的最大值
int i1, i2, i3, i_max;
cin >> i1 >> i2 >> i3;
i_max = max(i1,i2,i3);
cout << "i_max=" << i_max << endl;
//求三个浮点数的最大值
double d1, d2, d3, d_max;
cin >> d1 >> d2 >> d3;
d_max = max(d1,d2,d3);
cout << "d_max=" << d_max << endl;
//求三个长整型数的最大值
long g1, g2, g3, g_max;
cin >> g1 >> g2 >> g3;
g_max = max(g1,g2,g3);
cout << "g_max=" << g_max << endl;
return ;
}

模板函数也可以提前声明,不过声明时需要带上模板头,请看下面的例子:

#include <iostream>
using namespace std;
//声明模板函数
template<typename T> T sum(T a, T b);
int main(){
cout<<sum(, )<<endl;
return ;
}
//定义模板函数
template<typename T> T sum(T a, T b){
T temp = a + b;
return temp;
}

可以发现,模板头和函数定义(声明)是一个不可分割的整体,可以换行,但是中间不能有分号。

C++学习33 函数模板的更多相关文章

  1. C++模板学习:函数模板、结构体模板、类模板

    C++模板:函数.结构体.类 模板实现 1.前言:(知道有模板这回事的童鞋请忽视) 普通函数.函数重载.模板函数 认识. //学过c的童鞋们一定都写过函数sum吧,当时是这样写的: int sum(i ...

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

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

  3. C++学习之函数模板与类模板

    泛型编程(Generic Programming)是一种编程范式,通过将类型参数化来实现在同一份代码上操作多种数据类型,泛型是一般化并可重复使用的意思.泛型编程最初诞生于C++中,目的是为了实现C++ ...

  4. template学习一函数模板

    要点: 1.模板参数在实体化的时候不能自动类型转换,只有非模板函数才可以 例如: int max(int,int); template <class T> T max(T,T); 在调用的 ...

  5. C++学习笔记之模板(1)——从函数重载到函数模板

    一.函数重载 因为函数重载比较容易理解,并且非常有助于我们理解函数模板的意义,所以这里我们先来用一个经典的例子展示为什么要使用函数重载,这比读文字定义有效的多. 现在我们编写一个交换两个int变量值得 ...

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

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

  7. C++ 模板学习 函数模板、类模板、迭代器模板

    使用模板能够极大到使得代码可重用. 记录一下,方便后续使用. 1. 函数模板,支持多种类型参数 #include <stdio.h> #include <math.h> //函 ...

  8. C++学习笔记2_函数.函数指针.函数模板

    1. 内联函数void printAB(int a,int b){ cout<<(a)<<(b)<<endl;}int main(void){ for(int i= ...

  9. C++学习笔记:09 函数模板与类模板

    课程<C++语言程序设计进阶>清华大学 郑莉老师) 引入 考虑一个求绝对值函数myabs,对于int,double,float等数据类型需要重载多次,编写多个函数体.函数体逻辑代码完全一致 ...

随机推荐

  1. PHP strrpos strpos strstr strrchr 区别

    1. strstr string strstr ( string $haystack , mixed $needle [, bool $before_needle = false ] ) $needl ...

  2. hibernate--HQL语法与详细解释

    HQL查询: Criteria查询对查询条件进行了面向对象封装,符合编程人员的思维方式,不过HQL(Hibernate Query Lanaguage)查询提供了更加丰富的和灵活的查询特性,因此 Hi ...

  3. linux服务之nfs

    开发语言:rpc编程环境 服务器端:在linux平台下部署 客户端:一般是cli界面下的mount命令 相关包:rpcbind,nfs-utils 背景 http://nfs.sourceforge. ...

  4. php面向对象中的魔术方法中文说明

    1.__construct() 实例化对象是被自动调用.当__construct和以类名为函数名的函数 同时存在时调用__construct,另一个不背调用. 类名为函数名的函数为老版的构造函数. 2 ...

  5. js防止回车(enter)键提交表单及javascript中event.keycode

      如何防止回车(enter)键提交表单,其实很简单,就一句话.onkeydown="if(event.keyCode==13)return false;"把这句写在from标签里 ...

  6. HTML5之Canvas绘图实例——饼状图

    实现饼状分布画图(如下):调试环境:Firefox

  7. 车载凯立德导航地图更新以及DSA数据更新方法

    每年升级每次都去重新摸索,1年时间忘完了,遂决定把他写下来,我这就去实验,实验好了来补 第一步: 找最新的凯立德软件和地图版本号 方法:淘宝搜索, 例如:凯立德 2016,搜索结果会出现比如2016 ...

  8. C# 输出pdf文件流在页面上显示

    1 不调用itextsharp.dll的操作 /// <summary>        /// 生成pdf流        /// </summary>        /// ...

  9. Presto架构及原理

    Presto 是 Facebook 推出的一个基于Java开发的大数据分布式 SQL 查询引擎,可对从数 G 到数 P 的大数据进行交互式的查询,查询的速度达到商业数据仓库的级别,据称该引擎的性能是 ...

  10. 【mysql】mysql分表和表分区详解

    为什么要分表和分区? 日常开发中我们经常会遇到大表的情况,所谓的大表是指存储了百万级乃至千万级条记录的表.这样的表过于庞大,导致数据库在查询和插入的时候耗时太长,性能低下,如果涉及联合查询的情况,性能 ...