C++初阶:模版进阶【非类型模版参数】【模版的特化】【模版分离编译】

目录

一.非类型模版参数

二.模版的特化

2.1模版特化的概念

2.2函数模版的特化

2.3类模版特化

2.3.1全特化

2.3.2偏特化

2.3.3使用类模版特化

三.模版分离编译


一.非类型模版参数

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

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

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

	template<class T,size_t N = 10>class array{public:T& operator[](size_t index) {return _array[index]; }const T& operator[](size_t index)const {return _array[index]; }private:T _array[N];size_t _size;};

创建一个a1. 

 注意:

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

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

二.模版的特化

2.1模版特化的概念

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

比如:实现了一个专门用来进行小于比较的函数模板

template <class T>
bool Less(T left,T right)
{return left < right;
}

那么这个函数模板就不能处理地址比较的问题,比如:

int main()
{cout << Less(2, 1) << endl; //0Date d1(2022, 7, 8);Date d2(2022, 7, 7);cout << Less(d1, d2) << endl;//0Date* p1 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl;//可以比较,结果错误,结果为1return 0;
}

这里的问题就是我本来想要比较的是d1和d2,但是这里比较的是d1和d2的地址大小。这时候用上面的模版就不行了。

由上可知,函数模版并不能解决全部的内容,所以我们就有了模版特化。即:在原模板类的基础上,针对特殊类型所进行特殊化的实现方 式。模板特化中分为函数模板特化与类模板特化。

2.2函数模版的特化

函数模板的特化步骤:

1. 必须要先有一个基础的函数模板

2. 关键字template后面接一对空的尖括号<>

3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型

4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇 怪的错误。

在上面的Less模版后面加上:

template<>
bool Less<Date*>(Date* left, Date* right)
{return *left < *right;
}

这样如果参数是地址的话就会自动调用这个模版。

这里有一个需要注意的点,我在写Less的时候写的是T,实际上这样不好,如果是自定义类型还需要调用拷贝构造,最好写成:

template <class T>
bool Less(const T& left,const T& right)
{return left < right;
}

特化也要跟着改:

template<>
bool Less<Date*>(Date* const & left, Date* const & right)
{return *left < *right;
}

注意:

在模版中我的const是修饰left本身的,所以在特化的模版中我必须要遵守这个原则。const放在*的后面。

2.3类模版特化

2.3.1全特化

全特化就是模版参数列表中所有的参数都确定化。

template<class T1, class T2>
class Data
{
public:Data() {cout << "Data<T1, T2>" << endl; }
private:T1 _d1;T2 _d2;
};template<>
class Data<int, char>
{
public:Data() { cout << "Data<int, char>" << endl;}
private:int _d1;char _d2;
};void TestVector()
{Data<int, int> d1;Data<int, char> d2;
}int main()
{TestVector();//Data<T1, T2>//Data<int, char>return 0;
}

如果有函数模版参数列表中的类型对应,模版就不再实例化直接调用上面全特化的版本。

2.3.2偏特化

偏特化:任何针对模版参数进一步进行条件限制设计的特化版本。比如对于以下模板类:

对于偏特化有两种表现方式:

一种叫部分特化

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

还有一种是参数更进一步限制

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

//两个参数偏特化为指针类型 
template<class T1,class T2>
class Data<T1*, T2*>
{
public:Data(){cout << "Data<T1*, T2*>" << endl;}
private:T1 _d1;T2 _d2;
};//两个参数偏特化为引用类型
template <class T1, class 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;
};

2.3.3使用类模版特化

template<class T>
class Less
{
public:bool operator()(const T& x, const T& y) const{return x < y;}};int main()
{Date d1(2022, 7, 7);Date d2(2022, 7, 6);Date d3(2022, 7, 8);vector<Date> v1;v1.push_back(d1);v1.push_back(d2);v1.push_back(d3);// 可以直接排序,结果是日期升序sort(v1.begin(), v1.end(), Less<Date>());vector<Date*> v2;v2.push_back(&d1);v2.push_back(&d2);v2.push_back(&d3);// 可以直接排序,结果错误日期还不是升序,而v2中放的地址是升序// 此处需要在排序过程中,让sort比较v2中存放地址指向的日期对象// 但是走Less模板,sort在排序时实际比较的是v2中指针的地址,因此无法达到预期sort(v2.begin(), v2.end(), Less<Date*>());return 0;
}

所以就偏特化一下:

template<>
class Less<Date*>
{
public:bool operator()(const Date* x, const Date* y){return *x < *y;}
};

三.模版分离编译

假如有以下场景,模板的声明与定义分离开,在头文件中进行声明,源文件中完成定义:

// a.h
template<class T>
T Add(const T& left, const T& right);// a.cpp
template<class T>
T Add(const T& left, const T& right)
{return left + right;
}// main.cpp
#include"a.h"
int main()
{Add(1, 2);Add(1.0, 2.0);return 0;
}

为了避免这样的情况出现,可以:

1.将声明和定义放到一个文件 "xxx.hpp" 里面或者xxx.h其实也是可以的。推荐使用这种。

2. 模板定义的位置显式实例化。

显示实例化就是我们需要用谁就实例化一个它,比如上面的代码:

一个是int,一个是double类型的

template<class T>
T Add(const T& t1, const T& t2)
{return t1 + t2;
}template
int Add(const int& t1, const int& t2);template
double Add(const double& t1, const double& t2);

 这个很不方便,不建议使用。

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

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

相关文章

【数据结构算法经典题目刨析(c语言)】使用队列实现栈(图文详解)

目录 一.题目描述 二.解题思路 三.代码实现 &#x1f493; 博客主页&#xff1a;C-SDN花园GGbond ⏩ 文章专栏&#xff1a;数据结构经典题目刨析(c语言) 一.题目描述 二.解题思路 首先这道题需要我们使用两个队列来完成栈的实现, 这里我们的思路是, 栈的要求是后进先出, …

C语言进阶——一文带你深度了解“C语言关键字”(中篇6)

本篇文章记录我学习C语言进阶知识——C语言关键字&#xff0c;旨在记录分享&#xff0c;希望我的分享能带给你不一样的收获&#xff01; 目录 一、return关键字 二、const 关键字也许该被替换为 readolny &#xff08;一&#xff09;、 const 修饰的只读变量 &#xff08;二…

腾讯云COS和阿里云OSS在Springboot中的使用

引言&#xff1a;之前本来是用OSS做存储的&#xff0c;但是上线小程序发现OSS貌似消费比COS多一些&#xff0c;所以之前做了技术搬迁&#xff0c;最近想起&#xff0c;打算做个笔记记录一下&#xff0c;这里省去在阿里云注册OSS或腾讯云中注册COS应用了。 一、OSS 1、配置yml …

C ++ 也可以搭建Web?高性能的 C++ Web 开发框架 CPPCMS + MySQL 实现快速入门案例

什么是CPPCMS&#xff1f; CppCMS 是一个高性能的 C Web 开发框架&#xff0c;专为构建快速、动态的网页应用而设计&#xff0c;特别适合高并发和低延迟的场景。其设计理念类似于 Python 的 Django 或 Ruby on Rails&#xff0c;但针对 C 提供了更细粒度的控制和更高效的性能。…

Golang | Leetcode Golang题解之第330题按要求补齐数组

题目&#xff1a; 题解&#xff1a; func minPatches(nums []int, n int) (patches int) {for i, x : 0, 1; x < n; {if i < len(nums) && nums[i] < x {x nums[i]i} else {x * 2patches}}return }

【Python学习手册(第四版)】学习笔记19-函数的高级话题

个人总结难免疏漏&#xff0c;请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。 本文主要介绍函数相关的高级概念&#xff1a;递归函数、函数注解、lambda表达式函数&#xff0c;常用函数工具如map、filter、reduce&#xff0c;以及通用的函数设…

【超音速 专利 CN117576413A】种锂电池测试数据绑定方法、设备及存储介质

申请号CN202010618671.X公开号&#xff08;公开&#xff09;CN111967546A申请日2020.11.20申请人&#xff08;公开&#xff09;广州超音速自动化科技股份有限公司(833753)发明人&#xff08;公开&#xff09;张俊峰(总&#xff09;; 叶长春(总&#xff09;; 蓝明观 术语 治具…

【MySQL】数据库约束和多表查询

目录 1.前言 2.数据库约束 2.1约束类型 2.2 NULL约束 2.3 NUIQUE&#xff1a;唯一约束 2.4 DEFAULT&#xff1a;默认值约束 2.5 PRIMARY KEY&#xff1a;主键约束 2.6 FOREIGN KEY&#xff1a;外键约束 1.7 CHECK约束 3.表的设计 3.1一对一 3.2一对多 3.3多对多 …

vue3-02-vue3中的组件通信

目录 组件通信一、vue3组件通信和vue2的区别二、父子通信2.1 props通信1&#xff09;父→子传递数据&#xff08;父组件向子组件传递数据&#xff09;2&#xff09;子→父传递数据 2.2 v-model1&#xff09;v-model的本质2&#xff09;给modelValue起别名3&#xff09;$event 2…

用Python制作开心消消乐游戏|附源码

制作一个完整的“开心消消乐”风格的游戏在Python中是一个相对复杂的项目&#xff0c;因为它涉及到图形界面、游戏逻辑、动画效果以及用户交互等多个方面。不过&#xff0c;我可以为你提供一个简化的版本和概念框架&#xff0c;帮助你理解如何开始这个项目&#xff0c;并提供一…

英伟达元宇宙平台Omniverse的学习,技术调研

NVIDIA Omniverse™ 是一个基于 USD (Universal Scene Description) 的可扩展平台&#xff0c;可使个人和团队更快地构建自定义 3D 工作流并模拟大型虚拟世界。 Omniverse&#xff1a;三维设计协同、模拟的开发平台&#xff0c;实现3D实时渲染&#xff0c;RTX光线追踪技术 协…

职场英语培训柯桥外语学校学外语学英语到银泰泓畅学校

“工作量太大了”怎么说&#xff1f; 导致加班有一个非常大的因素就是&#xff1a; “工作量太大了&#xff01;” “ 注意&#xff1a;形容工作量太大不使用“big”一词&#xff0c;要用heavy&#xff0c;相应的要说工作量较小&#xff0c;可以用light. 工作量大/小 &…

数据中心互连的关键要素和核心技术

数据中心互连&#xff08;DCI&#xff09;依靠其关键要素和核心技术进行的高效、可靠和高速的连接&#xff0c;实现了数据中心跨区域连接的即时通信和数据交换&#xff0c;成为了现代数字通信基础设施的重要组成部分。从光模块和多路复用设备到网络协议和管理系统&#xff0c;D…

Leetcode75-5 反转字符串的元音字母

本质上来说就是反转字符串 一部分需要反转 一部分不动 思路: 1.用String字符串倒序拼接 就是过滤掉不是元音字符 然后把所有的字符&#xff08;非元音的直接复制过来 元音字母直接从反转的字符串里边复制即可&#xff09; 2.看了题解发现自己写的啰嗦了 就是一个双指针问题用…

酒店行业如何利用XML进行营销短信

随着信息社会的到来&#xff0c;消费者获得会所的服务也从单纯的电话方式&#xff0c;逐渐转变为电话、互联网、传真&#xff0c;群发短信等多种媒体并行的方式。今天着重介绍下酒店行业如何利用短信平台进行营销。 群发短信业务对酒店起到的效率&#xff1a;根据新产品或服务向…

java实现解析pdf格式发票

为了减少用户工作量及误操作的可能性&#xff0c;需要实现用户上传PDF格式的发票&#xff0c;系统通过解析PDF文件获取发票内容&#xff0c;并直接将其写入表单。以下文章记录了功能实现的代码。 发票样式 发票内容解析 引用Maven 使用pdfbox <dependency><groupI…

Spring Boot - 在Spring Boot中实现灵活的API版本控制(下)_ 封装场景启动器Starter

文章目录 Pre设计思路ApiVersion 功能特性使用示例配置示例 ProjectStarter Code自定义注解 ApiVersion配置属性类用于管理API版本自动配置基于Spring MVC的API版本控制实现WebMvcRegistrations接口&#xff0c;用于自定义WebMvc的注册逻辑扩展RequestMappingHandlerMapping的类…

前端CSS画图形

我以前一直很好奇&#xff0c;这些下拉菜单中的小箭头是怎么实现的&#xff0c;直到我看到了进阶的CSS。 OK&#xff0c;let me tell you hao to do. 想要实现这个效果&#xff0c;方法很多&#xff0c;我知道的就两个&#xff1a; 图片作弊法&#xff0c;CSS妙用法 图片作弊…

uni-app 开发App时调用uni-push 实现在线系统消息推送通知 保姆教程

一、引言 在开发App时避免不了需要推送系统通知&#xff0c;以提高用户的使用体验。在自己的一个工具型的小app上全流程接入了uni-push2.0的推送能力&#xff0c;做个记录&#xff0c;以防后期需要用到。在阅读本教程前最好先看看官方文档&#xff0c;结合官方文档使用&#xf…

下载免费设计素材,有这7个网站就够了

7个免费设计素材网站&#xff0c;这些网站提供了大量的免费资源&#xff0c;包括图片、字体、图标、模板等&#xff0c;涵盖了多种风格和主题&#xff0c;能够满足不同设计师和创作者的需求。无论是用于个人项目还是商业用途&#xff0c;这些网站都能给你提供丰富的选择&#x…