模板详解:泛型、函数\类模板、特化

文章目录

  • 泛型编程
  • 函数模板
    • 概念
    • 格式
    • 原理
    • 实例化
    • 参数匹配原则
  • 类模板
    • 格式
    • 实例化
  • 非类型模板参数
  • 模板的特化
    • 函数模板特化
    • 类模板特化
      • 全特化
      • 偏特化
  • 模板分离编译
  • 模板总结

泛型编程

函数重载的缺点

  • 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
  • 代码的可维护性比较低,一个出错可能所有的重载均出错。

告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码。

存在这样一个模具,通过给这个模具中填充不同的材料(类型),来获得不同材料的铸件(即生成具体类型的代码)。

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

模板分为函数模板类模板

函数模板

概念

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

格式

  • template 模板
template<typename T1,typename T2,......,typename Tn>
返回值类型 参数名(参数列表){}
template<typename T>
void Swap(T& left,T& right)
{T temp = left;left = right;right = temp;
}
typename是用来定义模板参数的关键字,也可以使用class(不能使用struct代替class)

原理

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式特定具体类型函数的模具,所以其实模板就是将本应该我们做的重复的事情交给了编译器。

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

实例化

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

模板参数类似函数参数,函数参数定义的是形参对象,模板参数定义的是类型。

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

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 = 9.9;//可以Add(a1,a2);Add(d1,d2);//报错//Add(a1,d1);return 0;
}

显式实例化:在函数名后的<>中只当模板参数的实际类型

template<class T>
T Add(const T& left,const T& right)
{return left + right;
}int main()
{int a = 1;double d = 2.2;int sub = Add<double>(a,b);return 0;
}

下面这种情况是显式实例化的主要用途。

template<class T>
T* Func()
{T* p = new T[10];return p;
}int main()
{int* n = Func<int>();return 0;
}

参数匹配原则

int Add(int left , int right)
{return left + right;
}template<class T> 
T Add(T left, T right) 
{return left + right; 
}
  • 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。

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

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

类模板

格式

template<class T1,class T2,......,class Tn>
class 类模板名
{//内成员定义
};

实例化

类模板实例化于函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

// vector是类名,Vector<int>才是类型
Vector<int> v1;
Vector<double> v2;

非类型模板参数

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

  • 类型形参:出现在模板参数列表中,跟在class或者typename之类的参数类型名称
  • 非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可以将该参数大工程常量来使用。
namespace yc
{template<class T,size_t N = 10>class array{private:T _array[N];size_t _size;}
}
  • 非类型的模板参数必须在编译期间就能确认结果

模板的特化

通常情况下,使用模板可以实现一些与类型无关的代码,但是对于一些特殊类型可能回得到一些错误的结果,需要特殊处理。

特化:在原模板类的基础上,针对特殊类型所进行特殊化的实现方式。模板特化中分为函数模板特化与类模板特化。

函数模板特化

步骤:

  1. 必须先有一个基础的函数模板
  2. 关键字template后面接一对空的尖括号< >
  3. 函数名后跟一对尖括号,间或好中指定需要特化的类型
  4. 函数形参表:必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误
	template<class T>bool Less(T left, T right){return left < right;}template< >bool Less<Date*>(Date* left, Date* rihgt){return *left < *right;}

一般情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都是将该函数直接给出。

bool Less(Date* left,Date* right)
{return *left < *right;
}
这种实现方式简单明了,代码的可读性高,容易书写,因为对于一些参数类型复杂的函数模板,特化时特别给出,因此函数模板不建议特化

类模板特化

全特化

  • 全特化:将模板参数列表中所有的参数都确定化
template<class T1,class T2>
class Date
{
public:Date(){cout << "class Date" << endl;}
private:T1 _d1;T2 _d2;
};template<>
class Date<int,char>
{
public:Date(){cout << "class Date<int,char>" << endl;}
private:int _d1;char _d2;
};int main()
{Data<int, int> d1;Data<int, char> d2;return 0;
}

偏特化

  • 偏特化:任何针对模板参数进一步进行条件限制设计的特化版本。

基础类模板

template<class T1,class T2>
class Date
{
public:Date(){cout << "class Date" << endl;}
private:T1 _d1;T2 _d2;
};

部分特化

  • 将模板参数类表中的一部分参数特化
template<class T1>
class Date<T1, char>
{
public:Date(){cout << "class Date<T1, char>" << endl;}
private:int _d1;char _d2;
};

参数进一步限制

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

模板分离编译

一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。

.h文件

.cpp文件


报错

C/C++程序要运行需要经过:预处理、编译、汇编、链接,这些步骤。
  • 在template.cpp文件中,编译器没有看到对Add模板函数的实例化,因此不会生成具体的加法函数
  • 在main.obj文件中调用的Add<int,int>,编译器在链接时才会找地址,但是这个函数并没有进行实例化,没有生成具体的代码,因此链接时报错。

解决办法

  1. 将声明和定义存放到一个文件中xxx.hpp里面或者xxx.h里面
  2. 模板定义的位置显式实例化。

模板总结

优点

  1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库STL因此而生
  2. 增强了代码的灵活性

缺点

  1. 模板会导致代码膨胀问题,也会导致编译时间变长
  2. 出现模板编译错误时,错误信息会非常混乱,不容易定义错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/843808.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何成为一名合格的JAVA程序员?

如何成为一名称职的Java编程人员&#xff1f;你一定不能错过的两本书。 第一本《Java核心技术速学版&#xff08;第3版&#xff09;》&#xff01; 1.经典Java作品《Java核心技术》的速学版本&#xff0c;降低学习门槛&#xff0c;帮助读者更容易学习Java&#xff0c;更快地把…

亚信安慧AntDB数据库与华为数据存储完成兼容性互认证

迎接数智时代&#xff0c;供给核心科技。日前&#xff0c;湖南亚信安慧科技有限公司&#xff08;简称&#xff1a;亚信安慧&#xff09;与华为技术有限公司&#xff08;简称&#xff1a;华为&#xff09;&#xff0c;完成了AntDB数据库产品与OceanProtect备份一体机及Oceanstor…

【算法】位运算算法——丢失的数字

题解&#xff1a;丢失的数字(位运算算法) 目录 1.题目2.题解3.位运算异或4.总结 1.题目 题目链接&#xff1a;LINK 2.题解 哈希数组查漏高斯求和排序位运算异或… 3.位运算异或 class Solution { public:int missingNumber(vector<int>& nums) {int ret 0;for…

界面组件Kendo UI for Angular教程 - 构建强大的PDF阅读器(二)

如今当用户需要处理PDF文件时&#xff0c;通常不得不下载应用程序或者浏览器插件&#xff0c;控制用户如何与PDF交互并不是一件容易的事。如果我们提供PDF作为内容&#xff0c;用户可以下载它并使用浏览器或PDF本身提供的控件进行交互。然而&#xff0c;一些企业可能希望控制用…

咖啡看书休闲时光404错误页面源码

源码介绍 咖啡看书休闲时光404错误页面源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;重定向这个界面 源码效果 源码下载 咖啡看书…

QT:协议概述

文章目录 概念帧结构&#xff1a;通信流程 示例&#xff1a;请求帧&#xff1a;响应帧&#xff1a; 概念 帧结构&#xff1a; | SOF (1 byte) | Frame Length (1 byte) | Command (1 byte) | Data Field (N bytes) | Checksum (1 byte) | 通信流程 示例&#xff1a; 请求帧&a…

电解式模具清洗机清洗模具的特点

电解式模具清洗机的特点可以归纳如下&#xff1a; 清洗效果显著&#xff1a; 电解式模具清洗机能够对模具进行深度清洁&#xff0c;有效去除模具表面的污垢、油污、除锈、硫化物、塑胶积碳等&#xff0c;使模具恢复原有的光洁度。清洗前后对比明显&#xff0c;模具更加光亮&am…

守护景区安全:探讨景区视频监控方案的搭建及必要性

据新闻报道&#xff0c;5月25日&#xff0c;安徽黄山景区内发生雷击&#xff0c;闪电击中飞来石景点的护栏&#xff0c;多人被碎石砸中受伤。景区工作人员表示&#xff0c;飞来石附近本就属于雷区&#xff0c;当天曾发过两次雷电预警。 随着旅游业的繁荣发展&#xff0c;越来越…

SpaceX间接「颠覆」了手机?星链如何直连手机通信?

SpaceX 旗下的星链项目推出了一个极具颠覆性的技术——direct to cell&#xff08;DTC&#xff09;&#xff0c;即通过卫星直接与手机建立通信。这项技术无需对手机进行任何改装&#xff0c;大多数普通手机都可以直接接入星链的卫星网络&#xff0c;实现全球范围内的手机信号覆…

c#对操作系统的时间无法更新?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

Linux 共享内存

Linux 共享内存 1. shmget函数2. shmat函数3. shmdt函数4. shmctl函数5. 注意&#xff1a; 多线程共享进程的地址空间&#xff0c;如果多个线程需要访问同一块内存&#xff0c;用全局变量就可以了。 在多进程中&#xff0c;每个进程的地址空间是独立的&#xff0c;不共享的&am…

152.找出峰值(力扣)

代码解决 class Solution { public:// 函数用于找到山峰元素的索引vector<int> findPeaks(vector<int>& mountain) {vector<int> result; // 用于存储山峰元素的索引// 遍历数组&#xff0c;从第二个元素到倒数第二个元素for(int i 1; i 1 < mount…

【机器学习】MS_MARCO_Web_Search解析说明

MS MARCO Web Search&#xff1a;引领大型模型与信息检索的新纪元 一、引言&#xff1a;大型模型与信息检索的挑战二、MS MARCO Web Search数据集的特点三、MS MARCO Web Search数据集的应用五、结语 在信息爆炸的时代&#xff0c;如何高效、准确地从海量数据中检索出有价值的信…

使用 Spring HATEOAS 开发 REST 服务-浅显的理解

随笔&#xff0c;简单理解 一、restful是什么 1、第一层次&#xff08;Level 0&#xff09;的 Web 服务只是使用 HTTP 作为传输方式&#xff0c;实际上只是远程方法调用&#xff08;RPC&#xff09;的一种具体形式。 SOAP 和 XML-RPC 都属于此类 2、第二层次&#xff08;Lev…

mybatis新增到数据库后返回当前ID

描述 在开发中&#xff0c;插入一条数据并返回当前的ID的场景很多 之前用mybatisPlus自带的api非常简单&#xff0c;调用完save or insert之后再getId即可。 今天使用mybatis的时候也遇到了这个场景&#xff0c;在此记录一下。 解决问题 直接再insert标签里面表明属性 核心…

EQMentor情商导师文心智能体:引领情商提升与人际关系改善的智能导师

目录 一、引言 情商的重要性 EQMentor智能体的诞生背景与目的 二、EQMentor智能体的概述 EQMentor智能体 简述EQMentor情商智能体的核心功能与特点 三、 EQMentor情商导师智能体 智能体的设计理念 智能体的功能特点 智能体的使用举例 四、结语 一、引言 情商的重要…

计算机网络学习笔记——网络层(b站)

目录 网络层概述 网络层提供的两种服务 ①面向连接的虚电路服务 ②无连接的数据报服务 IPv4 路由选择 路由器转发IP数据报 静态路由选择 动态路由选择 路由信息协议RIP 开放最短路径优先OSPF&#xff08;Open Shortest Path First&#xff09; 内部网关协议IGP&…

启智CV机器人,ROS

资料&#xff1a; https://wiki.ros.org/kinetic/Installation/Ubuntu https://blog.csdn.net/qq_44339029/article/details/120579608 装VM。 装ubuntu20.04 desktop.iso系统。 装vm工具&#xff1a; sudo apt update sudo dpkg --configure -a sudo apt-get autoremove o…

(1) 初识QT5

文章目录 Qt Quickdemo信号的命名方式 qml语言一个很重要的概念 qt 模块 Qt Quick Qt Quick是Qt5中⽤户界⾯技术的涵盖。Qt Quick⾃⾝包含了以下⼏种技术&#xff1a; QML-使⽤于⽤户界⾯的标识语⾔JavaScript-动态脚本语⾔Qt C具有⾼度可移植性的C库. 类似HTML语⾔&#xf…

nano机器人2:机械臂的视觉抓取

前言 参考链接: 【机械臂入门教程】机械臂视觉抓取从理论到实战 GRCNN 通过神经网络&#xff0c;先进行模型训练&#xff0c;在进行模型评估。 机械臂逆运动学求解 所有串联型6自由度机械臂均是可解的&#xff0c;但这种解通常只能通过数值解法得到&#xff0c;计算难度大&am…