源码编译环境:win10 x86
反汇编软件:IDA Pro(胖大妈)
第一次接触到模板是在C#的泛型编程,对其表面的理解是可以对一些约束范围内参数类型的方法进行重用,可以少写一些方法。在后面接触C++和汇编后开始疑惑,模板的原理?开始疑惑为什么模板的声明和实现分离后会导致不能正常链接的问题?模板的匹配机制是什么?在学习和研究中对测试代码进行反汇编查看其原理,然后把这些做一下笔记。模板编译原理暂时还不知道,后面找时间看看编译原理,在回来补充相关的笔记。
模板分函数模板和类模板,将函数或方法内部的参数和内部数据类型提取出来作为模板的参数,然后编译器为具体类型生成针对这个类型的方法体或者函数。
模板推荐写在同一文件里,一般会放在hpp文件里。
模板声明实现分离
明确生成模板实例:
//mb.h
template<typename T>
T Add(T v1, T v2);
//mb.cpp
#include "mb.h"
template<typename T>
T Add(T v1, T v2)
{
return v1+v2;
}
template int Add(int v1, int v2);//明确生成模板实例
//测试代码
int result= Add<int>(1, 2);
std::cout << result << std::endl;
如果在没有添加明确生成模板,代码将不能编译编译通过。
外名模板
//TODO 我自己电脑没编译通过 待补
模板参数自动推导
模板有自动推导功能,当模板自动推导出参数类型时,就可以不在模板实参列表中写明,这个时候模板可以像正常的方法或函数一样使用。
模板参数推导条件:
1.编译器只根据调用时给的实参列表来推导
2.与函数返回值无关
3.可推导参数必须位于参数列表末尾
T2 Test(T1 v1, T3 v3) {
T0 v0;
T2 v2 = T2(0);
return v2 - v1 - v3;
}
int main()
{
//第一个<double T2
//第二个int T0
//第三个double T1
//T3 自动推导
//tenp=-3.0d
double temp= Test<double,int,double>(0.1f, 2.0f);
}
结论:返回值T2是必须要给定类型的,T0虽然没有用到,但是模板里有,且是模板的第一个参数,T1不知道为啥不能自动推导。
证明T0必须指定类型过程:
当指定返回值类型,方法的参数列表自动推导的情况下,依然不能忽略T0参数类型。
template<typename T0,typename T1,typename T2=double,typename T3>
T2 Test(T1 v1, T3 v3) {
//同上
//T0 int,T1 float,T2 double,T3 float
}
int main()
{
double temp= Test<int>(0.1f, 2.0f);
}
反编译分析
template<typename T0,typename T1,typename T2=double,typename T3>
T2 Test(T1 v1, T3 v3) {
T0 v0;
T2 v2 = T2(0);
return v2 - v1 - v3;
}
int main()
{
double t1= Test<int>(0.1f, 2.0f);
double t2 = Test<int>(1, 2);
}
这是编译的源码,用两个float和两个int的模板进行对比。
这是反编译的源码,j_??$Test@HMNM@@YANMM@Z/j_??$Test@HHNH@@YANHH@Z这是方法名,模板的方法名,大概率也是和函数重载一样使用名字倾轧技术(name mangling)。
模板静态变量
普通函数中的静态变量可以解释为函数自有,不同函数之间的同名静态变量不通用,如果是模板的静态变量会怎么处理呢。
template<typename T0,typename T1,typename T2=double,typename T3>
T2 Test(T1 v1, T3 v3) {
static T0 v0=T0(0);
std::cout << "v0初始值:" << v0 << std::endl;
v0 += v1;
std::cout << "v0结果值:" << v0 << std::endl;
T2 v2 = T2(0);
return v2 - v1 - v3;
}
int main()
{
double t1= Test<int>(2.0f, 2.0f);
double t2 = Test<int>(3.0f, 4.0f);
double t3 = Test<int>(1, 2);
double t4 = Test<int>(3, 4);
}
我们修改一下上面的方法,在方法里声明一个静态变量,并且让这个静态变量与第一个参数进行加等于操作。
v0初始值:0
v0结果值:2
v0初始值:2
v0结果值:5
v0初始值:0
v0结果值:1
v0初始值:1
v0结果值:4
从中我们可以知道,前面两个模板共用了一个静态变量,后两个模板共用了一个静态变量。
反汇编分析:
从中我们可以发现,flaot模板调用的同一个方法(int同),那就和普通方法的处理规则一样了。
所以,我们写的模板方法,其本质就是编译器给我们生成了一个普通方法。
标签:int,T2,C++,基础知识,v0,v1,Test,模板 From: https://www.cnblogs.com/zjr0/p/16759173.html