如果想实现一个适应多种类型的交换数值的通用函数,没有接触模版之前,我首先想到的肯定是函数重载,但是这种情况使用函数重载就显得很吃力。因为:

1. 重载的函数仅仅只是类型不同,代码的复用率比较低,只要有新类型出现时,就需要增加对应的函数。

2. 代码的可维护性比较低,一个出错可能所有的重载均出错。

//又费劲,又低效!
void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}
void Swap(double& left, double& right)
{double temp = left;left = right;right = temp;
}
void Swap(char& left, char& right)
{char temp = left;left = right;right = temp;
}
//..............

为了解决类似的重复性工作,提高代码复用,以及泛型编程的实现,就引入了模版这个概念。

模版又有函数模版和类模版之分。接下来逐一举例介绍。

一、模版的概念

  • 函数模版的定义:函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
  • 函数模版的格式:
template<typename T>//template<typename T1, typename T2,......,typename Tn>
void Swap( T& left,  T& right)//返回值类型 函数名(参数列表)
{T temp = left;left = right;right = temp;
}//typename是用来定义模板参数关键字,也可以使用class(不能使用struct代替class)
  • 函数模版的原理:模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。

在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。

比如:当用double类型使用函数模板时,编译器通过对实参类型推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。

  • 函数模版的实例化:用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为;隐式实例化和显式实例化。

1.隐式实例化:让编译器根据实参推演模板参数的实际类型。

template<class T>
T Add(const T& left, const T& right)
{return left + right;
}
int main() {int a1 = 10, a2 = 20;double d1 = 10.0, d2 = 20.0;Add(a1, a2);Add(d1, d2);//Add(a1, d1);
/*
该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型 通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T, 编译器无法确定此处到底该将T确定为int 或者 double类型而报错
注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅
*/
// 此时有两种处理方式:1.用户自己来强制转化 2.使用显式实例化 Add(a, (int)d);return 0;
}

2.显示实例化:在函数名后的<>中指定模板参数的实际类型。

int main(void)
{int a = 10;double b = 20.0;//显式实例化 Add<int>(a, b); return 0;
}//如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

模板参数的匹配原则:

1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。

2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,那么将选择模板。

3.模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。

  • 类模版的格式:
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
  • 类模版的实例化:类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<> 中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
//Vector类名,Vector<int>才是类型
Vector<int> s1;Vector<double> s2;

二、模版的特化

模板参数分类类型形参非类型形参

类型形参:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。

非类型形参:就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。

PS:1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的。

2. 非类型的模板参数必须在编译期就能确认结果。

  • 模板特化的概念:通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果此时,就需要对模板进行特化。就是在原模板类的基础上,针对特殊类型所进行特殊化的实现方式。模板特化中分为函数模板特化与类模板特化。
  • 函数模版特化方法:1. 必须要先有一个基础的函数模板
                                     2. 关键字template后面接一对空的尖括号<>
                                     3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
                                     4. 函数形参表: 必须要和模板函数的基础参数类型完全相同。

PS:特化函数模版参数中若有const,则const修饰的是类型后面的变量,而不是类型。(该原理较复杂,先不考虑)

template<>
bool IsEqual<char*>(char*& left, char*& right)
{if(strcmp(left, right) > 0)return true;return false;
}
//PS:如果遇到某个棘手的特殊情况,实在不行就别特化了,直接给个重载完事
bool IsEqual(char* left, char* right)
{if(strcmp(left, right) > 0)return true;return false;
}
  • 类模板特化:全特化 偏特化
  • 全特化:全特化即是将模板参数类表中所有的参数都确定化。
template<>
class Data<int, char>
{
public:Data() {cout<<"Data<int, char>" <<endl;}
private:T1 _d1;T2 _d2;
};
  • 偏特化:任何针对模版参数进一步进行条件限制设计的特化版本。

偏特化有两种表现形式:

部分特化:将模板参数类表中的一部分参数特化。

//第二个参数特化为int型
template <class T1> class Data<T1, int>
{
public:Data() {cout<<"Data<T1, int>" <<endl;}
private:T1 _d1;int _d2;
};

参数更进一步的限制:偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本。

//两个参数偏特化为指针类型
template <typename T1, typename T2> class Data <T1*, T2*>
{
public:Data() {cout<<"Data<T1*, T2*>" <<endl;}
private:T1 _d1;T2 _d2;
};
//两个参数偏特化为引用类型
template <typename T1, typename T2>
class Data <T1&, T2&>
{
public:Data(const T1& d1, const T2& d2): _d1(d1), _d2(d2) {cout<<"Data<T1&, T2&>" <<endl;}
private:const T1 & _d1;const T2 & _d2;
};
void main()
{Data<double , int> d1; //调用上例中int版本Data<int , double> d2; //调用基础模版Data<int *, int*> d3; //调用特化的指针版本Data<int&, int&> d4(1, 2); //调用特化的指针版
}

关于模版的特化的应用类型萃取,将自己写的类型萃取与STL库中关于类型萃取的方法进行对比,看了STL库的方法之后觉得微软的程序员还是nb啊,写的程序真心简洁又高效,我还是差得远呢啊。下次另开一帖分析。

【C++初阶学习】之 懒人神器——模版(概念)相关推荐

  1. [ 懒人神器 ] —— OO一键build:.zip - .jar

    懒人神器 更新 大家注意一下,由于在写入MANIFEST的时候,Class-Path路径给的是 ../lib ,即上级目录的lib. 所以在对拍时如果手动移动了 jar包的位置,需要保证 lib/ 文 ...

  2. 暑期学习与“懒人电商”项目经验总结

    该文章作为本人暑期学习和实战的经验总结,既是笔记也是自己踩过的坑,分享给大家,如有错误请各位大佬指正. 一.HTML与CSS的知识点总结 (1)  autocomplete="off&quo ...

  3. 懒人神器 !一个创意十足的 Python 命令行工具

    作者 | 写代码的明哥 来源 | Python编程时光 当听到某些人说 xx 库非常好用的时候,我们总是忍不住想要去亲自试试. 有一些库,之所以好用,是对一些库做了更高级的封闭,你装了这个库,就会附带 ...

  4. 懒人神器:自动生成单元测试插件 Squaretest

    你是否常常因代码需编写单元测试而痛苦不堪,你是否因单元测试历史债而惆怅不断,Squaretest或许能帮你消除痛苦消除惆怅 前言 一.Squaretest是什么? 二.使用步骤 1.引入插件 2.使用 ...

  5. C语言的初阶学习(1)

    学习大纲 背景介绍 第一个C语言的程序 数据类型 变量和常量 变量的作用域和生命周期 常量 字符串+转义字符+注释 选择语句 循坏 函数 数组 操作符 常见关键字 #define 定义常量和宏 指针 ...

  6. C++初阶学习————二叉树进阶(二叉搜索树)

    二叉树进阶 二叉搜索树的概念 二叉搜索树的操作 基本框架 二叉搜索树的插入 二叉搜索树的查找 二叉搜索树的删除 整体代码 循环写法 递归写法 二叉搜索树的应用 二叉搜索树的性能分析 前面的文章介绍过二 ...

  7. C语言初阶学习-----01初识C语言

    这是初识C语言,对有一定基础的同学帮助很大,看不懂的到以后对应的章节会详细介绍. 1.数据类型 char //字符数据类型 short //短整型 int //整形 long //长整型 long l ...

  8. 《牛津字典精华总结》- 初阶系列 - 首页前言

    the Epilogue and Essential of 'Oxford Elementary Learner's Dictionary 2nd' 2008第一版总结,2011高阶版已经完全更新.完 ...

  9. 前端三剑客之 HTML - JavaEE初阶 - 细节狂魔

    文章目录 前言 后端 && 前端的部分历史 - java 关于网站搭建 正文开始! HTML 怎么编写一个HTML的代码? 小拓展: 快速编写 HTML 代码的小技巧 浏览器的开发者工 ...

  10. 读《大道至简—是懒人造就了方法 》有感

    读了大道至简第一章编程的精义之后,我觉得感触颇深,于是乎我又读了第二章是懒人造就了方法 ,之后果然没有让我失望,第二章写的也是非常的好,非常的吸引我. 第二章的开头便引用了李冰凿山的故事,在战国时代, ...

最新文章

  1. 专业软件测试,各类专业软件测试情况
  2. 大年初七,发paper、学Python...分享一下你的学习计划吧~
  3. MobPush精准把握用户的使用时间
  4. JavaScript学习知识点归纳
  5. UDP千兆以太网FPGA_verilog实现(三、代码前期准备-时序要求)
  6. fx 线程 弹窗_JFXPanel和FX Platform线程陷阱
  7. Kibana图形、报表分析
  8. 如何使用VUE做组件化开发 -- 思考篇
  9. 安全隐患分析和基本系统结构信息的收集
  10. python如何调用hslcommunication_C#读写PLC数据问题
  11. FMEA-MSR步骤五:风险分析(三)
  12. python怎样下载numpy_python下载numpy的方法是什么
  13. 如何生成SSH key?
  14. glide加载大图片白屏崩溃闪退
  15. 人工智能 | ShowMeAI资讯日报 #2022.06.13
  16. vim 删除当前词_键盘快捷键 - 在VIM中的光标之后或周围删除单词
  17. 计算任意文件夹大小 , 校验大文件的一致性 , 发抢红包程序
  18. GPS接收机设计(5)——定位解算
  19. Zookeeper客户端错误 Unable to read additional data from server
  20. 百度ai 人脸识别 java_百度ai 接口 人脸识别

热门文章

  1. android吃鸡闪退,绝地求生刺激战场iPhone6/6P闪退怎么办
  2. LG Sprite Software Root漏洞
  3. 使用Windows平台的VS2022来调试AKStream
  4. Zabbix 服务器修改时区时间
  5. 产品经理常用的三款工具
  6. 树形管理工具-美美哒
  7. 5GgNB和ng-eNB的主要功能
  8. Android 绘制简单的折线图
  9. offset 和 零点的一点解释
  10. LTE的CQI及下行码率计算