目录

  • 非类型模板参数
  • 模板特化
    • 全特化
      • 函数模板特化
      • 类模板特化
    • 偏特化
  • 模板的分离编译

非类型模板参数

我们平时使用的模板都是和类型有关的,但是也有不是类型也能当做模板来使用,而是在tmplate<>中定义一个变量并给定初始值,这种模板的参数称为非类型模板参数

例如在我们array静态数组中,底层的实现就使用到了非类型模板参数

使用示例:

void test()
{//定义10个int类型的静态数组//这是在栈上申请的,第二个值不宜太大//array<class T, size_t N>array<int, 10> arr;
}

使用注意事项:

  1. 不允许使用浮点数、类对象以及字符串作非类型模板参数
  2. 非类型的模板参数必须在编译期就能确认结果(传值)

模板特化

模板的特化分为全特化和偏特化
全特化:所有的模板类型都是具体的类型
偏特化:即存在具体类型参数,又存在非模板类型参数

全特化

函数模板特化

平时我们用的模板都是非特化模板,例如我们写一个isEqual判等函数。

template<class T>
bool isEqual(T a, T b)
{return a == b;
}

使用示例:

但是我们发现它们都是同类型的,如果不是同类型就无法实现不同类型之间的判等功能;但是我们想通过一个函数名就能解决这些不同类型之间的问题。
例如我们想判断两字字符数组中的内容是否相同

void test()
{char ptr1[] = "123";char ptr2[] = "123";int ret = isEqual(ptr1, ptr2);cout << ret << endl;
}

输出结果是:false;原因是当数组当做实参来传参时,就会退化为指针,此时再利用之前的isEqaul函数比较的是他们之间的地址而非内容。但是我们又想通过这种个函数来判断他们内容是否相等,这时候就可以通到特化模板
注意:前提必须存在一个通用的模板

//特化模板
template<> //参数不写
//函数名后加<确定的类型>(具体类型参数)
bool isEqual<char*>(char* a, char* b)
{return strcmp(a, b) == 0;
}

这时候就是相等的了

其实这里我们并非一定要使用特化模板,可以直接写一个普通函数,类型都为char*,所以特化模板用的比较少。

类模板特化

类模板特化的应用场景:类型萃取
我们看以下代码:

//通用类模板
template<class T1, class T2>
class D
{public:D(const T1& d1, const T2& d2):_d1(d1), _d2(d2){cout << "D(T1, T2)" << endl;}T1 _d1;T2 _d2;
};//类模板特化
template<>
class D<int, char>
{public:D(const int& d1, const char& d2):_d1(d1), _d2(d2){cout << "D(int, char)" << endl;}int _d1;char _d2;
};

创建对象时会因为通过具体传入的类型模板而调用不同类型的模板类

偏特化

拿上面代码做比较

//通用类模板
template<class T1, class T2>
class D
{public:D(const T1& d1, const T2& d2):_d1(d1), _d2(d2){cout << "D(T1, T2)" << endl;}T1 _d1;T2 _d2;
};//类模板全特化
template<>
class D<int, char>
{public:D(const int& d1, const char& d2):_d1(d1), _d2(d2){cout << "D(int, char)" << endl;}int _d1;char _d2;
};//类模板偏特化
template<class T1>
class D<T1, double>
{public:D(const T1& d1, const double& d2):_d1(d1), _d2(d2){cout << "D(T1, double)" << endl;}T1 _d1;double _d2;
};

运行结果:

偏特化模板作用:给模板参数做进一步的限制
改为指针类型

//限制作用
template<class T1, class T2>
class D<T1*, T2*>
{public:D(const T1& d1, const T2& d2):_d1(d1), _d2(d2){cout << "D(T1*, T2*)" << endl;}T1 _d1;T2 _d2;
};

模板的分离编译

我们通常习惯在.h文件中声明一个函数,在define.cpp文件中写出该函数的定义,在main.cpp文件中链接函数使用它们。但是要注意,使用了模板必须将函数或者类的声明和定义都放在一个文件中

fun.h文件

//函数模板声明
template<class T>
T fun(const T& a);

fun.cpp

#include <iostream>
#include "fun.h"
using namespace std;
template<class T>
T fun(const T& a)
{cout << a << endl;return a;
}

main.cpp

#include <iostream>
#include "fun.h"
using namespace std;int main()
{fun(1);return 0;
}

运行main.cpp

这是一个链接错误
在一个程序要运行起来要经过四个过程预处理->编译->汇编->链接。这里链接是将所有用到的函数地址符号等信息链接到同一个文件中整合成可执行文件。

错误原因分析:如果fun函数时一个普通的函数,在main.cpp中用到了该函数,会将该函数的地址信息符号加载到该文件中。但是该函数是一个模板函数,是在编译阶段中就要编译,但是在编译阶段中并没有使用的情况,所以此时就是一个空的符号信息。链接是就找不到该函数的符号信息,就会报链接错误。

解决办法1:声明与定义放在头文件中
fun.h文件

#include <iostream>
using namespace std;
template<class T>
T fun(const T& a)
{cout << a << endl;return a;
}

main.cpp文件

#include <iostream>
#include "fun.h"
using namespace std;int main()
{fun(1);return 0;
}

运行结果:

解决办法2:在定义的文件中使用该函数,让该函数被实例化出来(有符号信息,链接时就找得到)
fun.h文件

//函数模板声明
template<class T>
T fun(const T& a);

fun.cpp

#include <iostream>
#include "fun.h"
using namespace std;
template<class T>
T fun(const T& a)
{cout << a << endl;return a;
}
void test()
{fun(10);
}

main.cpp

#include <iostream>
#include "fun.h"
using namespace std;int main()
{fun(1);return 0;
}

运行结果:

C++ 泛型模板进阶相关推荐

  1. c语言泛型模板与this指针

    前言 上次我简单讲了一下c语言泛型的模板,这次详解C语言泛型模板的封装和this指针构造. 操作内容如下: #include <stdio.h> #include "templa ...

  2. 泛型模板和STL语法入门

    泛型模板和STL语法入门 STL简介 STL是Standard Template Library的简称,中文名标准模板库,惠普实验室开发的一系列软件的统称.它是由Alexander Stepanov. ...

  3. 学习笔记:C++初阶【C++入门、类和对象、C/C++内存管理、模板初阶、STL简介、string、vector、list、stack、queueu、模板进阶、C++的IO流】

    文章目录 前言 一.C++入门 1. C++关键字 2.命名空间 2.1 C语言缺点之一,没办法很好地解决命名冲突问题 2.2 C++提出了一个新语法--命名空间 2.2.1 命名空间概念 2.2.2 ...

  4. 《Java 核心技术卷1 第10版》学习笔记 ------ 泛型【进阶】

    这部分主要是结合 Java 虚拟机实现泛型的原理进一步研究如何更好的使用泛型. 8.5 泛型代码和虚拟机 虚拟机没有泛型类型对象---所有对象都属于普通类.所以编译器在编译的时候会进行类型擦除操作. ...

  5. 模板进阶——模板实参推断

    一.关键点 模板实参:模板参数T的实例类型,如int.string等 模板实参推断:从函数实参来确定模板实参的过程 模板类型参数与类型转换:const的转换.数组/函数到指针的转换 显式模板实参:当模 ...

  6. C++ 泛型编程的基础--模板初识及应用

    了解模板之前我们要先知道什么是泛型编程:泛型编程的代表作品STL是一种高效.泛型.可交互操作的软件组件.STL以迭代器 (Iterators)和容器(Containers)为基础,是一种泛型算法(Ge ...

  7. C++模板-泛型函数与泛型类

    泛型,在调用函数或使用该类时才指定特定的类型,可以避免重复写类似功能代码.那C++语言如何定义泛型呢? /* * Author:W: * 泛型-模板:只有在调用或使用该函数或类时,才确定类型 * 1. ...

  8. .NET 中的泛型 101

    1.1.1 摘要 图1 C# 泛型介绍 在接触泛型之前,我们编程一般都是使用具体类型(char, int, string等)或自定义类型来定义我们变量,如果我们有一个功能很强的接口,而且我们想把它提取 ...

  9. boost源码剖析之:泛型函数指针类boost::function(rev#3)

    boost源码剖析之:泛型函数指针类boost::function(rev#3) 刘未鹏 C++的罗浮宫(http://blog.csdn.net/pongba)   Note: 并非新作,03年曾放 ...

最新文章

  1. 机器学习的出现,是否意味着“古典科学”的过时?
  2. 业界丨一文看懂AI人才百万美元年薪因何而来?
  3. 黑马程序员Linux系统开发视频之创建守护进程模型
  4. (第一课)Python学习之蟒蛇绘制
  5. elastic学习笔记
  6. 字符串长度(PHP学习)
  7. 5.3矩阵乘积(三元组存储结构)
  8. 利用c语言面向对象编程,用C语言程序实现面向对象编程
  9. 离散数学:等价关系与集合覆盖
  10. 波轮全自动洗衣机分解与典型部件拆装技巧
  11. html英雄联盟网页,Html+Css+JQuery实现简易英雄联盟官网
  12. GitHub图片加载不出来解决方案(超详细图文教程)
  13. 氨基酸三字母序列转单字母序列
  14. 如何设置EXCEL里标题在每页都打印?
  15. VC++图像加密软件设计与实现
  16. 虚拟试戴用时尚拉近了粉丝和剧中人的距离
  17. 达梦数据库(DM8)基本使用
  18. matlab双线性变换切比雪夫2,语音信号滤波去噪——使用双线性变换法设计切比雪夫II型.doc...
  19. 用行列式展开计算n阶行列式【c++/递归】
  20. pandas读取excel使用read_excel()中的usecols参数读取指定的列

热门文章

  1. mysql set names没反应_MYSQL使用的时候遇到的一些问题
  2. 使用睡袋_宝宝睡袋使用心得
  3. mysql mvc javascript_MVC中用Jquery、JS和Ajax 实现分页 存储过程是用mysql写的。
  4. 安装mysql最后一步第二个打叉_Mysql安装到最后一步时。出现start service红叉   亲朋好友帮忙指导一下!谢谢! 百...
  5. php7.0 freetype_php7.0.5安装教程
  6. 台灯的内置和外置是什么意思_两款米家台灯:1S/Lite对比简评
  7. servlet中doPost()和doGet()
  8. Startlsback常见使用过程中的问题
  9. AESRijndael加密
  10. POJ3737 UmBasketella