C++初阶之模板进阶

个人主页:点我进入主页

专栏分类:C语言初阶  C语言进阶  数据结构初阶    Linux    C++初阶    算法

欢迎大家点赞,评论,收藏。

一起努力,一起奔赴大厂

目录

一.非类型模板参数

二.模板的特化

2.1引入

2.2全特化

2.3偏特化

三.模板的分离编译

3.1链接错误

3.2链接错误是如何产生的

3.3如何正确分离编译

3.4按需实例化


一.非类型模板参数

        非类型模板参数就是模板的参数有一个常量,我们可以参考下面的代码:

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

在C++98中我们只支持整形的做为非类型模板参数,在后面的一些版中开始支持其他的类型作为非类型模板参数。在库中我们就有一个类似的设计array这个,我们需要知道这个非常的不好用,因为它实现的功能使用vector就可以实现,而且array在栈上开辟的空间 ,非常容易造成栈溢出,所以可以说这个基本没有任何用处。

二.模板的特化

2.1引入

class Date
{
public:friend ostream& operator<<(ostream& _cout, const Date& d);Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}
private:int _year;int _month;int _day;
};ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}template<class T>
bool Less(T left, T right)
{
return left < right;
}
void test1()
{cout << Less(1, 2) << endl; // 可以比较,结果正确Date d1(2022, 7, 7);Date d2(2022, 7, 8);cout << Less(d1, d2) << endl; // 可以比较,结果正确Date* p1 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl; // 可以比较,结果错误}

在日期类中我们比较当传入的是值的时候可以比较正确,但是当我i们传入指针时,我们就不能保证这个正确了,这个主要就是比较的是地址,而不是值,因此我们需要特化。

2.2全特化

template<class T>
bool Less(T left, T right)
{cout << "Less(T left, T right)" << endl;return left < right;
}
template <>
bool Less(Date* left, Date* right)
{cout << "Less(Date * left, Date * right)" << endl;return *left < *right;
}

        我们需要在已经有的模板上再次写这个模板对它进行特化,但是template后面跟一个尖括号,尖括号里什么也不写,然后将类型写上,再写具体的代码。我们利用上面的代码运行可以看到:

在这里我们比较指针时会走我们的全特化,

2.3偏特化

        偏特化和全特化类似,它只是特化模板的一部分,它就是对参数进一步进行限制,我们可以看下面的代码:

template <class T1,class T2>
class A
{
public :A(){cout<<"A< T1,T2>" << endl;}
private:T1 _al;T2 _a2;
};template <class T1>
class A<T1,int>
{
public:A(){cout << "A< T1,int>" << endl;}
private:T1 _al;int _a2;
};template <class T1,class T2>
class A<T1*, T2*>
{
public:A(){cout << "A< T1*, T2*>" << endl;}
private:T1* _al;T2* _a2;
};
void test1()
{A<int, char> a1;A<int, int>a2;A<int*, int*>a3;
}

运行结果为

        在类的使用特化时我们需要在已有的类中再次定义这个类,但是类的后面需要加上括号,括号中的内容是类型,原来的类中的template中有几个参数它就有几个参数,特化的内容不同,没有限制的相同,特化的template中的尖括号为没有精准限制的(它不是一个模糊的,不明确的例如int等,但是参数是T*就需要将T写上)。

三.模板的分离编译

3.1链接错误

        我们将一个类进行分离编译,代码如下:

//.hnamespace bit
{template<class T, size_t N = 10>class array{public:int size() const;private:T _array[N];int _size=0;};
}//.cnamespace bit
{template<class T, size_t N >int array<T,N>::size() const {return _size;}
}

我们实例化一次运行可以看到出现了链接错误

链接错误就是找不到地址,我们可以实验一下,只在.h文件中写一个func函数,调用的时候就会出现链接错误,代码如下:

//.h为
void func();
//.c直接调用

这是由于在编译时有这个声明就可以了,连接时才会进行合并call地址,call的地址就是func定义的地方,但是没有定义,所以出现链接错误。 我们将func函数的定义写好后我们看汇编代码

 它会call一下地址。

3.2链接错误是如何产生的

        在编译阶段开始编译器会把模板进行实例化,由于我们是模板的分离编译,所以我们会造成在.h文件中没有定义的地址,.c文件中有定义但是不知道实例化成什么

3.3如何正确分离编译

        我们需要将声明和定义在同一个.h文件中,这样在编译阶段就会实例化,不需要在链接找地址,我们的代码如下:

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

3.4按需实例化

我们看代码

	template<class T, size_t N = 10>class array{public:int size() const;void print(){cout << size(2);}private:T _array[N];int _size=0;};template<class T, size_t N >int array<T, N>::size() const{return _size;}

我们可以看到print函数中是错误的,但是我们不适用print这个函数,编译器就不会报错,一旦使用这个就会出错,我们看两个实验:

bit::array<int> a1;
cout<<a1.size();

	bit::array<int> a1;a1.print();

造成这个结果的就是因为编译器会进行按需实例化,当我们需要的时候才会进行实例化,随着版本的更新,编译器在很久以前如果里面少写一个分号也可以编译过去,只要我们不去调用。

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

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

相关文章

八、函数和数组

8.1 函数 函数几乎是学习所有的程序设计语言时都必须过的一关。对于学习过其他的程序语言的用户来说&#xff0c;函数可能并不陌生。但是Shell中的函数与其他的程序设计语言的函数有许多不同之处。 8.1.1什么是函数 通俗地讲&#xff0c;所谓函数就是将一组功能相对独立的代码…

记忆力和人才测评,如何提升记忆力?

什么是记忆力&#xff1f; 如何通俗意义上的记忆力&#xff1f;我们可以把人的经历、经验理解成为一部纪录片&#xff0c;那么已经过去发生的事情&#xff0c;就是影片之前的情节&#xff0c;对于这些信息&#xff0c;在脑海里&#xff0c;人们会将其进行处理和组合&#xff…

SAP-CO成本控制概念之标准成本

“ 本篇介绍&#xff1a;标准成本的会计概念&#xff0c;标准成本的制定标准&#xff1b;通过结合会计标准成本的概念与SAP CO标准成本估算功能&#xff0c;更具象化的了解SAP如何实现标准成本管理&#xff0c;为后续学习SAP实际成本核算打下基础。” 01 — 背景需求 SAP实施…

2024年春招高薪职业报告:大模型算法研究员领跑

近日&#xff0c;脉脉高聘发布的研究报告《2024春招高薪职业和人才洞察》&#xff08;以下简称《洞察》&#xff09;显示&#xff0c;2024年一季度&#xff0c;大模型算法研究员新发岗位以平均月薪6.4万元领跑高薪岗位榜。受人才培养周期和技术门槛影响&#xff0c;人工智能行业…

机器学习大模型驱动:未来的趋势与应用

文章目录 &#x1f4d1;前言一、什么是机器学习大模型&#xff1f;1.1 大模型的特点1.2 大模型的技术基础 二、大模型的技术实现2.1 Transformer 架构2.2 预训练和微调2.3 模型并行和数据并行 三、大模型的应用场景3.1 自然语言处理&#xff08;NLP&#xff09;3.2 计算机视觉&…

vue3 使用css实现一个弧形选中角标样式

文章目录 1. 实现效果2. 实现demo 在前端开发中&#xff0c;ui同学经常会设计这样的样式&#xff0c;用于区分选中的状态 下面抽空简单些了一下&#xff0c;记录下&#xff0c;后面直接复制用 1. 实现效果 实现一个菜单切换&#xff0c;右下角有个角标的样式 2. 实现demo 主要…

Java进阶学习笔记20——枚举

认识枚举&#xff1a; 枚举是一种特殊的类。 枚举类的格式&#xff1a; 说明&#xff1a; 第一行是罗列枚举的对象名称。只能写合法的标识符&#xff08;名称&#xff09;&#xff0c;多个名称用逗号隔开。 这些名称本质上都是常量&#xff0c;每个变量都会记住枚举类的一个…

Optica数据库 (原OSA美国光学学会电子期刊)文献去哪里查找下载

Optica&#xff08;OSA&#xff09;数据库涵盖了光学和光子学理论研究和实际应用的各个领域&#xff0c;包括&#xff1a;光学设备、光学成像、光纤通信、分析方法、光通信、光纤、半导体激光、光传输、光学系统、计量学、带宽、量子电子学。 该库包括18种学会期刊&#xff08…

MVCC 原理分析、MySQL是如何解决幻读的

文章目录 一、前言回顾1.1 事务四大特性ACID1.2 并发事务问题1.3 事务隔离级别 二、MVCC2.1 为什么使用MVCC2.2 基本概念——当前读、快照读、MVCC2.2.1 当前读2.2.2 快照读2.2.3 MVCC 2.3 隐藏字段—— TRX_ID、ROLL_PTR2.4 undo log2.4.1 介绍2.4.2 版本链 2.5 Read View读视…

python写接口性能测试

import time import requestsdef measure_response_time(api_url):try:start_time time.time()response requests.get(api_url, timeout10) # 设置超时时间为10秒end_time time.time()response_time end_time - start_timeprint(f"接口 {api_url} 的响应时间为&#…

读书笔记-Java并发编程的艺术-第1章 并发编程的挑战

文章目录 1.1 上下文切换1.1.1 多线程一定快吗1.1.2 如何减少上下文切换 1.2 死锁1.3 资源限制的挑战 1.1 上下文切换 即时是单核处理器也支持多线程执行代码&#xff0c;CPU通过给每个线程分配CPU时间片来实现这个机制。时间片是CPU分配给多个线程的时间&#xff0c;因为时间…

C++拓展之scanf和printf

scanf和printf&#xff0c;这东西&#xff0c;说难也不难&#xff0c;可一旦深入学&#xff0c;学两天都可能学不完。 为了输入输出&#xff0c;我们要把这些占位符学一学。 我们来看看AI是怎么回答的。 Q&#xff1a;C格式化占位符有哪些&#xff1f; A&#xff1a;C中常用的…

【手把手带你搓组件库】从零开始实现Element Plus

从零开始实现Element Plus 前言亮点项目搭建1、创建项目初始化monorepo创建 .gitignore目录结构安装基础依赖配置文件创建各个分包入口utilscomponentscoreplaytheme 2、创建VitePress文档3、部署到Github Actions生成 GH_TOKENGitHub Page 演示 4、总结 前言 在本文中&#xf…

面向可复用性和可维护性的设计模式 课程学习总结

什么是设计模式 设计模式&#xff1a;在软件设计中给定上下文中常见问题的通用的、可重用的解决方案。 设计模式分类 1. 创建型模式——Creational patterns 关注对象创建的过程 1.1 工厂方法模式 定义用于创建对象的接口&#xff0c;但让子类决定要实例化哪个类。工厂方…

4.Redis之Redis的通用命令

0.Redis 实战操作 通过 redis-cli 客户端和 redis 服务器交互 涉及到很多的 redis 的命令 【redis 的命令非常非常多!!! 1.掌握常用命令(多操作多练习) 2.学会使用 redis 的文档-> 阅读文档, 是程序猿的基操!! redis 的命令非常非常多!!! 1.掌握常用命令(多操作多练习…

部署CNI网络组件+k8s多master集群部署+负载均衡

一、环境部署 主机服务 192.168.91.5 K8S集群master01192.168.91.8 K8S集群master02192.168.91.6K8S集群node01192.168.91.7K8S集群node02192.168.91.9 负载均衡nginxkeepalive01&#xff08;master&#xff09;192.168.91.10 负载均衡nginxkeepalive02&#xff08;backup&am…

编程实战:自己编写HTTP服务器(系列3:处理框架)

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 系列入口&#xff1a;编程实战…

TypeScript学习日志-第三十二天(infer关键字)

infer关键字 一、作用与使用 infer 的作用就是推导泛型参数&#xff0c;infer 声明只能出现在 extends 子语句中&#xff0c;使用如下&#xff1a; 可以看出 已经推导出类型是 User 了 二、协变 infer 的 协变会返回联合类型&#xff0c;如图&#xff1a; 三、逆变 infer…

pikachu靶场中的CSRF、SSRF通关

目录 1、CSRF介绍 2、CSRF&#xff08;get&#xff09; 3、CSRF&#xff08;post&#xff09; 4、CSRF Token 5、SSRF介绍 6、SSRF&#xff08;curl&#xff09; 7、SSRF&#xff08;file_get-content&#xff09; 8、CSRF与SSRF的区别 最近在学习CSRF、SSRF漏洞&#…

Boyer-Moore投票算法

摩尔投票法&#xff0c;又称为博耶-摩尔多数投票算法&#xff0c;是一种用于在一组数据中寻找多数元素(出现次数超过一半的元素)的算法。该算法的效率非常高&#xff0c;时间复杂度为O(n)&#xff0c;空间复杂度为O(1)&#xff0c;适合处理大数据量的情况。 步骤 首先定义两个…