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. java程序显示log日志信息的方法

    首先需要引入maven依赖 <dependency> <groupId>commons-logging</groupId> <artifactId>co ...

  2. Netfilter 之 五个钩子点

    概述 在协议栈的三层IPv4(IPv6还没看,不清楚)数据包的处理过程中,可能经过Netfilter的五个钩子点,分别为NF_INET_PRE_ROUTING.NF_INET_LOCAL_IN.NF_ ...

  3. Nginx-HTTP之ngx_http_top_header_filter

    1. ngx_http_top_header_filter 该链表主要是用于构造响应消息的消息报头. ngx_http_top_header_filter 单链表有如下模块插入了操作: ngx_htt ...

  4. CPU分支预测器

    两篇结合就ok啦 1.https://www.jianshu.com/p/be389eeba589 2.https://blog.csdn.net/edonlii/article/details/87 ...

  5. word2vec原理与代码

    目录 前言 CBOW模型与Skip-gram模型 基于Hierarchical Softmax框架的CBOW模型 基于Negative Sampling框架的CBOW模型 负采样算法 结巴分词 wor ...

  6. ubuntu 17.04 添加用户到sudo组

    最近在系统中安装了KVM和docker,用KVM的时候好好的,可以直接使用virsh等命令.但是安装了docker,使用docker命令时需要在前面加上sudo,这个用起来就挺麻烦的,于是想到dock ...

  7. kotlin class

    每个次构造函数需要委托给主构造函数, 可以直接委托或者通过别的次构造函数间接委托.委托到同一个类的另一个构造函数用 this 关键字即可 class Person { constructor(pare ...

  8. yum 保存下载的rpm 包

    yum 保存下载的rpm 包 1 [root@bogon pluginconf.d]# vim /etc/yum.conf [main]cachedir=/var/cache/yum/$basearc ...

  9. Linux(CentOS / RHEL 7) 防火墙

    CentOS / RHEL 7 防火墙 Table of Contents 1. 简述 2. 常用基本操作 2.1. 查看防火墙状态 2.2. 开启防火墙 2.3. 关闭防火墙 2.4. 开机自动启动 ...

  10. backupAgent节点

    在<application>节点中有一个非常重要的属性,那就是backupAgent. 1.backupAgent简介 Androidd:backupAgent用来设置备份代理.对于大部分 ...