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

前言

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

我们为什么需要模板

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

  1. int max(int a, int b)
  2. {
  3. return a < b ? b : a;
  4. }
  5.  
  6. float max(float a, float b)
  7. {
  8. return a < b ? b : a;
  9. }

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

什么是模板

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

函数模板

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

  1. template<typename T>
  2. T max(T a, T b)
  3. {
  4. return a < b ? b : a;
  5. }

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

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

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

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

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

  1. template<typename T, int i>
  2. T create()
  3. {
  4. T value();
  5. return value + i;
  6. }
  7.  
  8. int main()
  9. {
  10. float f1 = create<float, >(); // f1 == 1.0
  11. float f2 = create<float, >(); // f2 == 2.0
  12. }

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

  1. float create() // create<float, 1>
  2. {
  3. float value();
  4. return value + ;
  5. }
  6.  
  7. float create() // create<float, 2>
  8. {
  9. float value();
  10. return value + ;
  11. }

我们总结一下函数模板的语法,模板定义由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. GAN︱生成模型学习笔记(运行机制、NLP结合难点、应用案例、相关Paper)

    我对GAN"生成对抗网络"(Generative Adversarial Networks)的看法: 前几天在公开课听了新加坡国立大学[机器学习与视觉实验室]负责人冯佳时博士在[硬 ...

  2. MFC 多线程及线程同步

    一.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消息机制,通常 ...

  3. 奶瓶beini系统

    奶瓶(beini)这个系统,是一款基于 Tiny Core Linux 搭建的无线网络安全测试系统,当然由于它是用来安全测试的系统,因此在安全方面自然有着强大的功能.而且,这个系统非常简便易学,因此现 ...

  4. Srtuts2实现登录界面(不连接数据库)报错(二)

    二月 28, 2014 11:37:29 下午 org.apache.catalina.core.AprLifecycleListener init 严重: An incompatible versi ...

  5. offline页面开发常用方法及页面控件验证

    offline页面开发常用方法及页面控件验证,对一些CheckBoxList操作进行封装,新人可以直接使用该代码. 1.返回上一页网址 /// <summary> /// Descript ...

  6. freemarker写select组件(三)

    freemarker写select组件 1.宏定义 <#macro select id datas value="" key="" text=" ...

  7. Flex内存泄露解决方法和内存释放优化原则

    Flex内存泄露解决方法和内存释放优化原则 你对Flex内存泄露的概念是否了解,这里和大家分享一下Flex内存释放优化原则和Flex内存泄露解决方法,希望本文的介绍能让你有所收获. Flex内存释放优 ...

  8. Xenu-web开发死链接检测工具应用

    Xenu 是一款深受业界好评,并被广泛使用的死链接检测工具. 时常检测网站并排除死链接,对网站的SEO 非常重要,因为大量死链接存在会降低用户和搜索引擎对网站的信任,web程序开发人员还可通过其找到死 ...

  9. 【转载】Spark学习——spark中的几个概念的理解及参数配置

    首先是一张Spark的部署图: 节点类型有: 1. master 节点: 常驻master进程,负责管理全部worker节点.2. worker 节点: 常驻worker进程,负责管理executor ...

  10. 【HDU2255】奔小康赚大钱

    题面 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓 ...