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

文章目录

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

泛型编程

函数重载的缺点

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

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

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

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

模板分为函数模板类模板

函数模板

概念

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

格式

  • 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;更快地把…

uni-app增加home图标,实现回到功能主页(九)

最近在优化一个uni-app项目,项目中有许多设备需要点检,点检完成后可以继续点检;最后导致页面跳转用的是 uni.navigateTo({ url:"/pages/dianjian/dianjian/dianjianInfo?datatype="+this.datatype }); 众所周知,这个会将页面推入堆栈中,结合…

嵌入式开发面试问题总结(持续更新)

面试问题总结 c/c 封装、继承和多态 封装&#xff1a;将属性和方法封装起来&#xff0c;并加以权限区分。继承&#xff1a;子类继承父类的特征和行为&#xff0c;复用了从基类复制而来的数据成员和成员函数&#xff08;基类私有成员无法被访问&#xff09;&#xff0c;其中构…

高通Android 12/13打开省电模式宏开关

1、添加到SettingsProvider配置项宏开关 默认节电助手自动开启百分比battery saver frameworks\base\packages\SettingsProvider\src\com\android\providers\settings\DatabaseHelper.java private void loadGlobalSettings(SQLiteDatabase db) {在该方法中添加 ......final i…

人脸识别--DeepFace(五)

DeepFace 是由 Facebook 于 2014 年开发的一种深度学习模型&#xff0c;用于人脸识别和验证。它是当时最先进的人脸识别系统之一&#xff0c;展示了深度学习在计算机视觉任务中的巨大潜力。DeepFace 的主要贡献在于它使用了深度卷积神经网络&#xff08;CNN&#xff09;来学习人…

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

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

一千题,No.0036(D进制的A+B)

输入两个非负 10 进制整数 A 和 B (≤230−1)&#xff0c;输出 AB 的 D (1<D≤10)进制数。 输入格式&#xff1a; 输入在一行中依次给出 3 个整数 A、B 和 D。 输出格式&#xff1a; 输出 AB 的 D 进制数。 输入样例&#xff1a; 123 456 8输出样例&#xff1a; 1103…

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

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

Bash Bug(破壳漏洞,Shellshock) - CVE-2014-6271

Shellshock 在本文中&#xff0c;我们将深入探讨2014年发现的破壳漏洞&#xff08;CVE-2014-6271&#xff09;&#xff0c;这是一个影响Unix和类Unix系统的Bash&#xff08;Bourne Again SHell&#xff09;的重大安全漏洞。我们将讨论这个漏洞的工作原理&#xff0c;展示如何复…

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

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

从入门到精通:Linux进程控制

在计算机操作系统中&#xff0c;进程&#xff08;Process&#xff09;是一个非常重要的概念。进程控制是操作系统的核心功能之一&#xff0c;对于Linux操作系统尤其如此。本文将详细介绍Linux操作系统中的进程控制&#xff0c;从入门到精通&#xff0c;涵盖进程的创建、终止、等…

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

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

Java中的多态性:理解和应用面向对象的核心概念

多态性是面向对象编程&#xff08;OOP&#xff09;的核心概念之一&#xff0c;在Java中扮演着至关重要的角色。多态允许对象采取多种形式&#xff0c;增强了程序的灵活性和可扩展性。本文将深入探讨Java中的多态性&#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;实现全球范围内的手机信号覆…

MySQL:将空字符串改为NULL

在关系性数据库中Oracle&#xff0c;MySQL&#xff0c;MssSQL中&#xff0c;空字符串()和NULL是两个概念 空字符串顾名思义代表是一个为空的字符串&#xff0c;并不是没有值&#xff0c;而NULL代表没有值或未知值 所以有很多小伙伴&#xff0c;使用IFNULL&#xff0c;ISNULL&…

如何从异步调用中返回响应

想象一下,你打电话给朋友并让他帮你查一些资料。虽然这可能需要一段时间,但你会在电话里等待,直到朋友给你需要的答案。这就是同步调用的行为: function findItem() {var item;while (item_not_found) {// 查找}return item; }var item = findItem(); // 使用 item doSome…

一个 ComfyUI 节点,它使用 的 LLMs 功能对您的输入执行任何操作以进行任何类型的输出-anynode

网址 https://github.com/lks-ai/anynode 一个 ComfyUI 节点&#xff0c;它使用 的 LLMs 功能对您的输入执行任何操作以进行任何类型的输出。