转载请保留以下声明
  作者:赵宗晟
  出处:http://www.cnblogs.com/zhao-zongsheng/p/8493398.html

前言

有些人提到C++模板就会下意识地觉得可怕、看不懂、避而远之。其实模板并不复杂,而且熟练后可以用在日常工作中,可以帮助我们重用代码,让代码更简洁、易读、可维护。希望这个系列的文章,能够让更多人发现模板的魅力,帮助大家写出更高质量的代码。

我们为什么需要模板

我们有时候会遇到这样的情况:同样的函数,我们要为不同的类型写不同的版本,内容与逻辑都是一摸一样的,只有他们的类型不一样。比如我们写一个max函数,传入两个数字,返回大的数字。很自然地,两个参数的类型和返回的类型必须是相同的。如果不使用模板,我们需要使用函数重载,为不同的类型写不同的函数:

int max(int a, int b)
{
return a < b ? b : a;
} float max(float a, float b)
{
return a < b ? b : a;
}

这里我只写了2个函数,实际上short, long, unsigned, double等等类型都需要专门的max函数,结果就是需要写十几个几乎一摸一样的代码。如果函数功能更复杂一些,函数实现需要更多行,就会出现大量冗余重复的代码,而且不容易维护,很容易出错。这个时候如果我们能够根据特定的模板批量生成一系列代码,将会方便很多。为此,我们可以使用C++中的模板

什么是模板

顾名思义,模板就是编译器生成代码用的模子。模板有两类,函数模板和类模板(C++14开始出现了变量模板,不过不在此讨论)。如果想要生成函数代码,则需要用函数模板,如果想要生成类定义,则需要用到类模板。这篇文章会先介绍函数模板,下篇文章再介绍类模板。

函数模板

我们可以为上面的一系列max函数写一个函数模板。

template<typename T>
T max(T a, T b)
{
return a < b ? b : a;
}

我们暂时不细说语法,先看一看大致的样子,其实函数模板的长相和普通的函数是很像的。

好了,我们已经定义了一个函数模板,那么怎么去生成函数代码?事实上我们不需要做额外的事情,如果我们使用了max函数,编译器就会自动帮我们生成对应类型的代码。函数模板的使用方式很简单,只需要在模板的名字后面写一对尖括号,尖括号内写上实参列表就可以使用了。

double d = max<double>(1.2, 2.4);

编译器看到这一行,就会自动帮我们生成double版本的max函数,生成出来的函数等价于把函数模板中的所有T都替换成double。在这里max<double>可以看做是double版本的max函数的函数名,我们甚至还可以用&max<double>来获取这个函数的地址。

我们来看一个更复杂的例子

template<typename T, int i>
T create()
{
T value();
return value + i;
} int main()
{
float f1 = create<float, >(); // f1 == 1.0
float f2 = create<float, >(); // f2 == 2.0
}

这个例子里面我们定义了一个create函数模板,根据模板创建并使用了两个函数create<float, 1>和create<float, 2>。要注意的是,这两个函数是不同的函数,有不同的函数体,和不同的函数地址。他们两个分别等价于

float create()    // create<float, 1>
{
float value();
return value + ;
} float create() // create<float, 2>
{
float value();
return value + ;
}

我们总结一下函数模板的语法,模板定义由template关键字开始,后面跟着一对尖括号,尖括号里面是模板形参列表,也就是模板的参数。模板形参列表的写法和函数形参列表的写法是很相似的。都是“类型 参数名, 类型 参数名, ...”这种形式。上面的例子中,模板形参列表就是“typename T, int i”。我们注意到,模板形参列表需要为每个形参指定一个类型,这个是因为形参不一定是C++类型,还可以是具体的值,例如数字,指针等等。如果形参是一个类型,则需要使用typename关键字来表示形参的类型,如果形参是一个值,则需要写上这个值的类型。在使用模板的时候,要在模板的名字后面加一对尖括号,尖括号里面是模板实参列表,在上面的例子中,实参列表就是“float, 1”和“float, 2”。与函数调用类似,使用模板的时候编译器会检查实参列表的类型与形参列表的类型是否匹配,不匹配的话会报错。

使用函数模板的优点

我们可以从上面的例子中看出,用函数模板更方便简洁,不需要重复写类似的重载函数。除此外,因为函数代码是在使用的时候生成出来的,所以如果我们没有使用这个函数,编译器就不会生成这个代码,这样我们可以减小程序的大小。例如,我们使用了max<double>,但是没有使用max<int>,那么程序中只有max<double>函数,不会有max<int>函数。

C++模板入门教程(一)——模板概念与基本语法的更多相关文章

  1. FineReport----报表模板入门教程1

    FineReport就一款类Excel操作界面的报表工具,通过拖拖拽拽简单实现报表制作,实现数据展示.数据查询.数据录入功能,并且支持图形多样化展示. 一.入门小例子 1. 打开设计器 启动FineR ...

  2. git 入门教程之基本概念

    基本概念 了解工作区,暂存区和版本库的区别和联系有助于我们更好理解 git 的工作流程,了解命令的操作意图. git 和其他版本控制系统如 svn 的不同之处就是有暂存区的概念. 基本概念 工作区 | ...

  3. 一步步Cobol 400 上手自学入门教程01 - 基础概念

    先学习基础概念 1.COBOL字符:包含: User-defined words 用户定义字符 ŸSystem-names ŸReserved words 关键字 2.用户定义字符User-defin ...

  4. MobX快速入门教程(重要概念讲解)

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/7372119.html 一:Mobx工作流程图 二:MobX涉及到的概念 1:状态state 组件中的数据. 2 ...

  5. 程序员,一起玩转GitHub版本控制,超简单入门教程 干货2

    本GitHub教程旨在能够帮助大家快速入门学习使用GitHub,进行版本控制.帮助大家摆脱命令行工具,简单快速的使用GitHub. 做全栈攻城狮-写代码也要读书,爱全栈,更爱生活. 更多原创教程请关注 ...

  6. Linux Cgroup 入门教程:cpuset

    这是 Cgroup 系列的第四篇,往期回顾: Linux Cgroup 入门教程:基本概念 Linux Cgroup 入门教程:CPU Linux Cgroup 入门教程:内存 通过上篇文章的学习,我 ...

  7. pageadmin CMS网站制作教程:模板概念解释

    pageadmin CMS网站建设教程:模板概念解释 1.模板页 又叫视图页面,PageAdmin后台栏目或信息中用到的模板页面的统称,格式必须是.cshtml后缀文件,前端人员制作的页面默认都是ht ...

  8. mui初级入门教程(六)— 模板页面实现原理及多端适配指南

    文章来源:小青年原创发布时间:2016-07-26关键词:mui,webview,template,os,多端适配转载需标注本文原始地址: http://zhaomenghuan.github.io. ...

  9. CPF 入门教程 - 设计器和模板库的使用(五)

    CPF netcore跨平台UI框架 系列教程 CPF 入门教程(一) CPF 入门教程 - 数据绑定和命令绑定(二) CPF 入门教程 - 样式和动画(三) CPF 入门教程 - 绘图(四) CPF ...

随机推荐

  1. yii学习笔记--使用gii快速创建控制器和模型

    配置gii 'gii'=>array( 'class'=>'system.gii.GiiModule', 'password'=>'123456',//使用gii的密码 // If ...

  2. Java中过滤出字母、数字和中文的正则表达式

    1.Java中过滤出字母.数字和中文的正则表达式 (1)过滤出字母的正则表达式 [^(A-Za-z)] (2)过滤出数字的正则表达式 [^(0-9)] (3)过滤出中文的正则表达式 [^(\\u4e0 ...

  3. Linux查看用于终止进程命令

    Linux查看用于终止进程命令 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ ps PID TTY TIME CMD 2576 pts/0 00:00:00 ...

  4. 把连续动态bmp转换为avi

    把动态bmp24转换为avi BYTE tmp_buf[1024*768*4]; //生成avi void BMPtoAVI(CString szAVIName, CString strBmpDir) ...

  5. Python内置函数详解——总结篇

    2个多月来,将3.5版本中的68个内置函数,按顺序逐个进行了自认为详细的解析,现在是时候进行个总结了.为了方便记忆,将这些内置函数进行了如下分类:     数学运算(7个)     类型转换(24个) ...

  6. monkeyrunner_获取apk的包名和activity名

    一.使用adb获取单个apk的包名和Activity名称: 1.配置adb环境 a. 我的电脑点击右键-属性-高级-环境变量; b.  环境变量中新建PATH,变量值输入adb.exe工具所在目录; ...

  7. 【BZOJ4805】欧拉函数求和(杜教筛)

    [BZOJ4805]欧拉函数求和(杜教筛) 题面 BZOJ 题解 好久没写过了 正好看见了顺手切一下 令\[S(n)=\sum_{i=1}^n\varphi(i)\] 设存在的某个积性函数\(g(x) ...

  8. 【HDU4622】Reincarnation(后缀自动机)

    [HDU4622]Reincarnation(后缀自动机) 题面 Vjudge 题意:给定一个串,每次询问l~r组成的子串的不同子串个数 题解 看到字符串的大小很小 而询问数太多 所以我们预处理任意的 ...

  9. 【BZOJ3932】任务查询系统(主席树)

    [BZOJ3923]任务查询系统(主席树) 题面 Description 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei ...

  10. [BZOJ1087] [SCOI2005] 互不侵犯King (状压dp)

    Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包 ...