1、通过一个简单的例子来理解模板的用途:

模板为不同类型的数据生成操作相同或相似的函数。
弱语言如Python,可以使用一种函数来应对各种类型,但是C++就不得不为不同的类型编写相似的函数。模板的作用就是把这一步骤交给编译器去执行,让这些函数在编译器生成。
 
2、模板参数的自动推导
原则:凡是可以推导出来的模板参数“值”就无需在模板实参列表中写明。
规则一:编译器值根据函数调用时给出的实参列表来推导模板参数值,与函数参数类型无关的模板参数无法推导
规则二:与函数返回值相关的模板参数其值也无法推导
规则三:所有可以推导模板参数必须是连续位于模板参数列表尾部,中间不能有不可退到的模板参数。
举例:
 

test1~test3的分析过程如下:
第一,sv2是返回值,我们不能通过返回值的类型推导模板参数的值,所以T2无法推导出来;
第二,T0使用的地方是函数内部的一个变量,也不是函数的参数,所以无法通过sv0的类型推导出T0的值
第三,以test1为例,func的三个参数分别是1,2,3整型,所以可以推断出T1、T3、T4是int。因为T0和T2无法推导出,所以必须在func<>中明确给出。而由于要根据声明的顺序给出,不能跳过T1,所以func<>中的三个类型分别是T0、T1、T2的类型。
 
3、模板参数的默认值
形如:
有两个具有默认类型,其它三个可以从函数参数类型推导,所以不需要尖括号:
 
4、模板参数的静态变量
这一讲用来说明,如果模板参数的值是相同的,那么模板函数实例就只生成一个,不会重复生成。
 

test1和test2中的static变量进行了递减,说明test1和test2中的func是同一个。这也就说明,func的实例是依具体的参数而决定的,如果模板参数值一样,编译器就不会重复生成函数实例。
我们逆向也可以知道,这里的两个函数是相同的:

用IDA加载进符号表之后,会更清晰一点:

5、问题一:模板函数应该如何在头文件里声明?
 
如果只是在头文件里添加一个函数模板的声明:

这样编译工程是肯定能编译通过的。因为,编译器在编译test.h和test.cpp文件时,只是读到了func0函数模板的实现,并没有读到任何需要生成函数模板的实例的语句,所以不会生成任何func0函数实例。

但是如果在main.cpp中添加了func0,那么此时就要生成一个func0的具体实例了,但test.h文件中只有一个func0函数模板的声明,编译器并没有生成实际的函数实例,只好在mian函数中的func0处预留一个链接调用,等待在链接过程中找到函数实现。因为你这里调用时,实际上是调用一个func0<int>(0); 但是test.cpp里并没有这个函数的实力。就会报错(这种错误很隐晦,很难排查):

所以,我们的解决办法是明确地在头文件中声明具体的实例。编译器就会生成这个函数模板实例了:

问题二:
但是,如果你想再生成func0(float)、func0(char)那么就得在头文件中添加两个实例的声明。但这貌似违背了最初使用模板的目的。
解决的办法就是把模板的实现也包含到头文件中,这样main函数把test.h包含进来了,编译器在编译时就知道main函数要用到一个func0<int>实例了,就可以编译出func0<int>实例了。//如果你把代码放到cpp里,那就是等到连接时去做事儿,如果放到h文件里,那就是在编译时去做事儿。
 
问题三:
产生重复模板实例问题。但这个问题会由连接器解决。
比如,新增加caller.obj

原有的main.obj中也有

但我们会发现main和caller.obj最终调用的都是caller中的func0:

就是因为连接器把caller0和main中的func0合并成了一个,合并规则是函数名、模板实参列表以及参数列表相同。
 
 
 
 

《深入实践C++模板编程》之一——Hello模板的更多相关文章

  1. 《深入实践C++模板编程》之三——模板参数类型详解

    非类型模板参数 和 模板型模板参数 整数以及枚举类型:指向对象或者函数的指针:对对象或函数的引用:指向对象成员的指针.统称为非类型模板参数. 模板型模板参数,是指模板参数还可以是一个模板.   1.整 ...

  2. 《深入实践C++模板编程》之四——特例

    1. 所谓模板特例,是针对符合某种条件的模板参数值集合另外声明的模板实现变体. template<typename T> class my_vector; template<> ...

  3. 《深入实践C++模板编程》之二——模板类

    1.类的模板的使用 类,由于没有参数,所以没有模板实参推导机制. #include <stdexcept> template<typename T> class my_stac ...

  4. c++模板编程-typename与class关键字的区别

    最近一直在研究c++模板编程,虽然有些困难,但希望能够坚持下去.今天,在书上看见一个讨论模板编程typename与class两个关键字的区别,觉得挺有意义的,就把它们给总结一下. 先看一个例子: te ...

  5. C++ 11可变参数接口设计在模板编程中应用的一点点总结

    概述 本人对模板编程的应用并非很深,若要用一句话总结我个人对模板编程的理解,我想说的是:模板编程是对类定义的弱化. 如何理解“类定义的弱化”? 一个完整的类有如下几部分组成: 类的名称: 类的成员变量 ...

  6. C++模板编程中只特化模板类的一个成员函数

    模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数.类模板中大多数成员函数的功能可能是一模一样的,特化时我们可能只需要重新实现1.2个成员函数即可.在这种情况下,如果全 ...

  7. C++之模板编程

    当我们越来越多的使用C++的特性, 将越来越多的问题和事物抽象成对象时, 我们不难发现:很多对象都具有共性. 比如 数值可以增加.减少:字符串也可以增加减少. 它们的动作是相似的, 只是对象的类型不同 ...

  8. c++ 基于Policy 的 模板编程

    在没真正接触c++  模板编程之前.真的没有想到c++ 还能够这么用.最大的感触是:太灵活了,太强大了. 最初接触模板威力还是在Delta3d中,感觉里面的模板使用实在是灵活与方便,特别是dtAI中使 ...

  9. C++模板编程中只特化模板类的一个成员函数(花样特化一个成员函数)

    转自:https://www.cnblogs.com/zhoug2020/p/6581477.html 模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数.类模板中大多 ...

随机推荐

  1. Linux如何修改环境变量

    如果想要环境变量永久生效可以修改下面两个文件中的任何一个: 1 /etc/profile 2 .bash_profile 其中,/etc/profile是全局的环境变量,对所有用户生效,而.bash_ ...

  2. webpack入门-配置项

    一.常用配置 1.enter(表示入口,webpack从此处开始构建) 2.output(配置输出结果) 3.module(关于模块的配置,内部可以配置loader) 4.resolve(配置寻找模块 ...

  3. Qt VS MFC

    最近用了一段时间Qt,觉得网上这篇文章讲述Qt与MFC之间的区别很到位,分享一下. ----------------------------------原文---------------------- ...

  4. quartz 定时器时间表达式

    按顺序依次为 秒(~) 分钟(~) 小时(~) 天(月)(~,但是你需要考虑你月的天数) 月(~) 天(星期)(~ =SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT) .年份(-) ...

  5. MySQL5.7 创建及查看数据库

    1.创建数据库语句create database语句是在MySQL实例上创建一个指定名称的数据库.create schema语句的语义和create database是一样的. 2.语法解析 CREA ...

  6. CentOS linux7 磁盘分区

    常用命令 df [选项] [文件] -a  显示全部文件系统 -h 方便阅读方式显示 -l 只显示本地文件系统 -T 显示文件系统类型 fdisk  /dev/sda1

  7. [Ubuntu]18安装百度网盘

     1.下载客户端 下载地址: 选择linux版本,我选择的是deb格式,下载就可以了. 2.安装 进入下载目录,点击右键,选择在终端打开. 之后输入 以下代码愉快的安装就好了 注意:dpkg后面跟的文 ...

  8. iOS tableHeaderView有默认高度?

    在给tableView设置tableHeaderView的时候发现,如果设置tableView.tableHeaderView = [UIView new] , 这里未设置tableView的高度,但 ...

  9. 007-IP报文协议

    一.概述 IP协议是将多个包交换网络连接起来,它在源地址和目的地址之间传送一种称之为数据包的东西,它还提供对数据大小的重新组装功能,以适应不同网络对包大小的要求. IP不提供可靠的传输服务,它不提供端 ...

  10. Djang之ModelForm组件的简单使用

    ModelForm组件的简单使用 models.py from django.db import models class UserInfo(models.Model): username = mod ...