c++的学习之路:19、模板

摘要

本章主要是说了一些模板,如非类型模板参数、类模板的特化等等,文章末附上测试代码与导图

目录

摘要

一、非类型模板参数

二、类模板的特化

1、概念

2、函数模板特化

3、类模板特化

三、模板的分离编译

1、什么是分离编译

2、模板的分离编译

四、模板总结

1、优点

2、缺点

五、代码

1、test.cpp

2、Date.h 

3、Date.cpp

六、导图

一、非类型模板参数

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

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

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

类型模板在之前写代码的时候经常使用,就是template<class T>在之前代码中经常使用这个,这个就是模板可以让编译器自动推演类型,从而方便使用,如下方代码如果想要定义一个数组指定他的大小,在以前我是用宏定义的,但是如果需要修改的话还是挺麻烦的,还是需要一个一个去更改也会很麻烦这时,c++提出了一个该念叫做非类型模板。

#define n 10
namespace ly
{
    template<class T>
    class arry
    {
    private:
        int    arr[n];
    };
}

非类型模板 就是如下方代码这种给一个缺省值就可以利用这个缺省值去进行初始化数组的就是非类型模板,但是需要注意一下两点:

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

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

template<class T,size_t n=10>
    class arry
    {
    private:
        int    arr[n];
    };

二、类模板的特化

1、概念

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板,这里就不得不说说之前所用到的仿函数,在优先队列那里实现的代码就用了仿函数,但是有些情况就需要提出说一下,如下方代码和下方图片我想要的结果是小于,结果他却比较了指针大小这就不是我想要的,这时就需要对模板进行特化。即:在原模板类的基础上,针对特殊类型所进行特殊化的实现方式。模板特化中分为函数模板特化与类模板特化。

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

cout << ly::Less(1, 2) << endl;
    Date d1(2022, 7, 7);
    Date d2(2022, 7, 8);
    cout << ly::Less(d1, d2) << endl;
    Date* p1 = &d1;
    Date* p2 = &d2;
    cout << ly::Less(p1, p2) << endl;

2、函数模板特化

函数模板的特化步骤:

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

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

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

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

下面的代码就是特化的写法,这个写法是祖师爷规定的,他的形式就是这种的。

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

3、类模板特化

类模板特化又分为全特化和偏特化,偏特化就是部分特化,全特化就是全部特化,如下方测试的代码所示。

下方这个代码就是全特化,全特化就是把参数全部都进行实例化,如下方带就是实例化成了int和char这样编译器就更加适配这个就不会在进行自动推演生成了。

namespace ly
{
    template<class T1, class T2>
    class Data
    {
    private:
        T1 _d1;
        T2 _d2;
    };
    template<>
    class Data<int, char>
    {
    private:
        int _d1;
        char _d2;
    };
}

int main()
{
    ly::Data<int, int> d1;
    ly::Data<int, char> d2;
}

 偏特化也就是部分特化,这种只进行部分的实例化,就是偏特化的使用方式。

template<class T1>
    class Data<T1, char>
    {

    private:
        int _d1;
        char _d2;
    };

三、模板的分离编译

1、什么是分离编译

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

也就是之前经常用的头文件与c文件分离使用,这个就是一个分离编译使用,相当于c语言中说的低耦合,也就是模块化。

2、模板的分离编译

但是在写c++的时候除了写日期类的时候用的还是分离,在后面写模板的时候就没有分离了,因为在我当时试了,报错搞了半天也没解决,我上网去查就查出来了一种解决方发,模板定义的位置显式实例化,但是特别麻烦,所以我就选择放在一个文件夹里面,然后我去看了一下stl的源码,代码如下,如图一就是放在类里面定义的,它定义的也就是少的就是放在类里,相当于内联长的也是放在外面写,如下方图二代码所示。

 

四、模板总结

1、优点

1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生

2. 增强了代码的灵活性

2、缺点

1. 模板会导致代码膨胀问题,也会导致编译时间变长

2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误

五、代码

1、test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
#include <vector>using namespace std;//namespace ly
//{
//	template<class T,size_t n=10>
//	class arry
//	{
//	private:
//		int	arr[n];
//	};
//	template<class T>
//	bool Less(T left, T right)
//	{
//		return left < right;
//	}
//	template<>
//	bool Less<Date*>(Date* left, Date* right)
//	{
//		return *left < *right;
//	}
//}
//
//int main()
//{
//	cout << ly::Less(1, 2) << endl;
//	Date d1(2022, 7, 7);
//	Date d2(2022, 7, 8);
//	cout << ly::Less(d1, d2) << endl;
//	Date* p1 = &d1;
//	Date* p2 = &d2;
//	cout << ly::Less(p1, p2) << endl;
//}namespace ly
{template<class T1, class T2>class Data{private:T1 _d1;T2 _d2;};/*template<>class Data<int, char>{private:int _d1;char _d2;}*/template<class T1>class Data<T1, char>{private:int _d1;char _d2;};
}int main()
{ly::Data<int, int> d1;ly::Data<int, char> d2;
}

2、Date.h 

#pragma onceclass Date
{
public:// 获取某年某月的天数int GetMonthDay(int year, int month);// 全缺省的构造函数Date(int year = 1, int month = 1, int day = 1);// 拷贝构造函数Date(const Date& d);// 赋值运算符重载Date& operator=(const Date& d);// 析构函数~Date();// 日期+=天数Date& operator+=(int day);// 日期+天数Date operator+(int day);// 日期-天数Date operator-(int day);// 日期-=天数Date& operator-=(int day);// 前置++Date & operator++();// 后置++Date operator++(int);// 后置--Date operator--(int);// 前置--Date& operator--();// >运算符重载bool operator>(const Date& d);// ==运算符重载bool operator==(const Date& d);// >=运算符重载bool operator >= (const Date& d);// <运算符重载bool operator < (const Date& d);// <=运算符重载bool operator <= (const Date& d);// !=运算符重载bool operator != (const Date& d);// 日期-日期 返回天数int operator-(const Date& d);//打印void Print();
private:int _year;int _month;int _day;
};

3、Date.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include "Date.h"
#include <iostream>
#include <string>
#include <vector>using namespace std;// 全缺省的构造函数
Date::Date(int year, int month, int day)
{_year = year;_month = month;_day = day;
}
// 拷贝构造函数
Date::Date(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;
}
// 析构函数
Date::~Date()
{_year = 0;_month = 0;_day = 0;
}
// 赋值运算符重载
Date& Date::operator=(const Date& d)
{if (this!=&d){_year = d._year;_month = d._month;_day = d._day;}return *this;
}
// 日期+=天数
Date& Date::operator+=(int day)
{if (day < 0){return *this -= (-day);}_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);++_month;if (_month == 13){++_year;_month = 1;}}return *this;
}
// 日期+天数
Date Date::operator+(int day)
{Date tmp(*this);tmp += day;return tmp;
}
// 日期-天数
Date Date::operator-(int day)
{Date tmp(*this);tmp -= day;return tmp;
}
// 日期-=天数
Date& Date::operator-=(int day)
{if (day < 0){return *this += (-day);}_day -= day;while (_day <= 0){--_month;if (_month == 0){--_year;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;
}
// 前置++
Date& Date::operator++()
{*this += 1;return *this;
}
// 后置++
Date Date::operator++(int)
{Date tmp(*this);*this += 1;return tmp;
}
// 后置--
Date Date::operator--(int)
{Date tmp(*this);*this -= 1;return tmp;
}
// 前置--
Date& Date::operator--()
{*this -= 1;return *this;
}
// <运算符重载
bool Date::operator < (const Date& d)
{if (_year < d._year){return true;}else if (_year == d._year && _month < d._month){return true;}else if (_year == d._year && _month == d._month && _day < d._day){return true;}else{return false;}
}
// ==运算符重载
bool Date::operator==(const Date& d)
{return _year == d._year&& _month == d._month&& _day == d._day;
}
// <=运算符重载
bool Date::operator <= (const Date& d)
{return *this < d || *this == d;
}
// !=运算符重载
bool Date::operator != (const Date& d)
{return !(*this == d);
}
// >运算符重载
bool Date::operator>(const Date& d)
{return !(*this <= d);
}
// >=运算符重载
bool Date::operator >= (const Date& d)
{return !(*this < d);
}
// 日期-日期 返回天数
int Date::operator-(const Date& d)
{Date max = *this;Date min = d;int flag = 1;if (*this < d){max = d;min = *this;flag = -1;}int n = 0;while (min != max){++min;++n;}return n * flag;
}
// 获取某年某月的天数
int Date::GetMonthDay(int year, int month)
{static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30,31 };int day = days[month];if (month == 2&& ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))){day += 1;}return day;
}
//打印
void Date::Print()
{cout << "Print:" << _year << '/' << _month << '/' << _day << endl << endl;
}

六、导图

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

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

相关文章

ip地址切换器安卓版,保护隐私,自由上网

在移动互联网时代&#xff0c;随着智能手机和平板电脑的普及&#xff0c;移动设备的网络连接变得愈发重要。为了满足用户在不同网络环境下的需求&#xff0c;IP地址切换器安卓版应运而生。本文将以虎观代理为例&#xff0c;为您详细解析IP地址切换器安卓版的功能、应用以及其所…

克服与新一代人工智能部署相关的数据挑战

随着商界领袖逐渐了解该技术的力量和潜力&#xff0c;人们对 ChatGPT 等生成式人工智能工具的潜力的兴趣正在迅速上升。 这些工具能够创建以前属于人类创造力和智力领域的输出&#xff0c;有潜力改变许多业务流程&#xff0c;并成为每个人&#xff08;从作家和创作者到程序员和…

蓝桥杯加训

1.两只塔姆沃斯牛&#xff08;模拟&#xff09; 思路&#xff1a;人和牛都记录三个数据&#xff0c;当前坐标和走的方向&#xff0c;如果人和牛的坐标和方向走重复了&#xff0c;那就说明一直在绕圈圈&#xff0c;无解 #include<iostream> using namespace std; const i…

openstack-认证服务

整个OpenStack是由控制节点&#xff0c;计算节点&#xff0c;网络节点&#xff0c;存储节点四大部分组成。 openstack重要集成组件: Nova-计算服务&#xff1b;Neutron-网络服务&#xff1b;Swift-对象存储服务&#xff1b;Cinder-块存储服务&#xff1b;Glance-镜像服务Keys…

LeetCode-118. 杨辉三角【数组 动态规划】

LeetCode-118. 杨辉三角【数组 动态规划】 题目描述&#xff1a;解题思路一&#xff1a;Python 动态规划解题思路二&#xff1a;解题思路三&#xff1a;0 题目描述&#xff1a; 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&…

C语言进阶课程学习记录-第27课 - 数组的本质分析

C语言进阶课程学习记录-第27课 - 数组的本质分析 数组实验-数组元素个数的指定实验-数组地址与数组首元素地址实验-指针与数组地址的区别小结 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程&#xff0c;图片全部来源于课程PPT&#xff0c;仅用于个人学习记录 数组 实验-数…

Hot100【十一】:编辑距离

// 定义dp[i][j]: 表示word1前i个字符转换到word2前j个字符最小操作数 // 初始化dp[m1][n1] class Solution {public int minDistance(String word1, String word2) {int m word1.length();int n word2.length();// 1. dp数组int[][] dp new int[m 1][n 1];// 2. dp数组初…

IO流:将文件从A复制到B,并实现复制过程进度条的实现

private static boolean copyFile(String strFileA, String strFileB) {// 使用try资源块 ,其中创建的流对象可以自动关闭try (FileInputStream inputStream new FileInputStream(strFileA); // 输入流FileOutputStream outputStream new FileOutputStream(strFileB) // 输…

【Linux】进程的状态(运行、阻塞、挂起)详解,揭开孤儿进程和僵尸进程的面纱,一篇文章万字讲透!!!!进程的学习②

目录 1.进程排队 时间片 时间片的分配 结构体内存对齐 偏移量补充 对齐规则 为什么会有对齐 2.操作系统学科层面对进程状态的理解 2.1进程的状态理解 ①我们说所谓的状态就是一个整型变量&#xff0c;是task_struct中的一个整型变量 ②.状态决定了接下来的动作 2.2运行状态 2.…

【闲聊】-网页划词翻译插件

英文之痛 作为程序猿&#xff0c;常常需要接触外文网站&#xff0c;以前很痛苦&#xff0c;现在大模型时代有很多智能工具可以直接翻译&#xff0c;翻译的虽然越来越好&#xff0c;但是还是不如直接看英文能理解本义&#xff0c;相信我&#xff0c;看翻译的理解和看原文的理解…

龙迅LT2611UXC 2 PORT LVDS桥接到HDMI 2.0,内置MCU,颗自行操作

龙迅LT2611UXC描述&#xff1a; LT2611UXC是一个高性能的LVDS到HDMI2.0的转换器&#xff0c;用于STB&#xff0c;DVD应用程序。LVDS输入可以配置为单端口或双端口&#xff0c;有1个高速时钟通道&#xff0c;3~4个高速数据通道&#xff0c;最大运行1.2Gbps/通道&#xff0c;可支…

gpu模拟器总体流程

1、开显存空间&#xff0c;初始化 这里显存就是运行模拟器的机器 2、创建页表&#xff0c;开设备端空间并复制数据 虚拟地址 3、划分形状&#xff0c;传入内核函数&#xff0c;形状参数和设备端数据地址、执行计算 4、复制数据回主机端&#xff0c;释放gpu资源

手写简易操作系统(二十五)--文件系统第三部分

前情提要 一、文件写入 1.1、file的写入 文件写入比较复杂&#xff0c;函数行数相当多 /*** description: 把buf中的count个字节写入file,成功则返回写入的字节数,失败则返回-1 * param {file*} file 文件* param {void*} buf 缓存* param {uint32_t} count 写入的字节数…

基于Java+SpringBoot+Vue民宿预约管理系统(源码+文档+部署+讲解)

一.系统概述 随着社会的不断进步与发展&#xff0c;人们经济水平也不断的提高&#xff0c;于是对各行各业需求也越来越高。利用计算机网络来处理各行业事务这一概念更深入人心&#xff0c;由于工作繁忙以及其他的原因&#xff0c;到实体店进行预约也是比较难实施的。如果开发一…

LLM Agents调研

LLM Agents调研 1、从 Copilot 到 Agent2、Agent概述3、agent框架2.1 框架介绍2.2框架对比 4、应用场景3.1single-agent应用3.2multi-agent 应用 5、agent功能选型参考&#xff1a; 1、从 Copilot 到 Agent 参考&#xff1a;https://mp.weixin.qq.com/s/vVUO-WRkp8FS3wKcfgu45…

【Vue3 + ElementUI】表单校验无效(写法:this.$refs[‘formName‘].validate((valid) =>{} ))

一. 表单校验 1.1 template模块 el-form 中 若校验&#xff0c;ref 和 rules 必须要有 <template><div style"padding:20px"><el-form ref"formName" :model"form" :rules"formRules" label-width"120px"…

C++进阶之路---何为智能指针?

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、为什么需要智能指针&#xff1f; 下面我们先分析一下下面这段程序有没有什么内存方面的问题&#xff1f;提示一下&am…

医疗图像分割 | 基于Pyramid-Vision-Transformer算法实现医疗息肉分割

项目应用场景 面向医疗图像息肉分割场景&#xff0c;项目采用 Pytorch Pyramid-Vision-Transformer 深度学习算法来实现。 项目效果 项目细节 > 具体参见项目 README.md (1) 模型架构 (2) 项目依赖&#xff0c;包括 python 3.8、pytorch 1.7.1、torchvision 0.8.2(3) 下载…

数据仓库实践

什么是数据仓库&#xff1f; 数据仓库是一个用于存储大量数据并支持数据分析与报告的系统。它通常用于集成来自不同来源的数据&#xff0c;提供一个统一的视图&#xff0c;以便进行更深入的分析和决策。 数据仓库的主要优势&#xff1f; 决策支持&#xff1a;为企业决策提供可靠…

渗透知识贴

文章目录 基础知识同源策略 常见web漏洞SQL注入漏洞 web中间件 基础知识 同源策略 同源策略是目前所有浏览器都实行的一种安全政策。A网页设置的 Cookie&#xff0c;B网页不能打开&#xff0c;除非这两个网页同源。所谓同源&#xff0c;是指&#xff1a;协议、端口、域名相同…