【模板特性补充】

news2024/10/5 19:16:22

目录:

  • 前言
  • 一、非类型模板参数
    • 使用方法
    • 使用场景
  • 二、模板特化
    • (一)函数模板特化
    • (二)类模板特化
      • 1.全特化
      • 2.偏特化
    • 使用场景
  • 三、模板分离编译
      • 1. 什么是分离编译
      • 2.模板的分离编译
      • 3.解决方法
  • 四、模板总结

前言

打怪升级:第42天
在这里插入图片描述

一、非类型模板参数



#define CNT1 10
#define CNT2 60

const int cnt1 = 10;
const int cnt2 = 60;

void Test_const1()
{
	int arr[CNT1];
	float arr[CNT1];
	double arr[CNT1];
	int arr[CNT2];

	int arr[cnt1];
	int arr[cnt2];
}


在这里插入图片描述

使用方法

模板参数分为:类型模板 和 非类型模板;
类型模板:类(函数)模板参数列表中 跟在 class、typename之后的参数,eg:template<calss T>
非类型模板:类(函数)模板参数列表中 的整形类型的常量,egtemplate<size_t n = 10>

#include<iostream>
using namespace std;
#include<vector>
#include<array>

//template<class T = int, size_t n = 10>
template<class T = vector<int>, char n = 10>
class AA
{
public:
	T at(size_t i)
	{
		return _arr[i];
	}

private:
	T _arr[n];
};

void Test_AA1()
{
	AA<int> a1;

	AA<int, 5>a2;

	cout << a2.at(5) << endl;
}

这里是引用
注意一点:非类型模板参数作为常量使用,但是在模板参数列表中进行声明时并没有加 const
咱们祖师爷当时就是这么设定的,我们使用的时候就牢牢记住:的屁股-> 龟定。

使用场景

在这里插入图片描述
虽然这个array模板第一次看起来感觉:欧呦,不错呦~,
但是,如果了解stl的朋友应该会想到另外一个容器:vector,既然我们已经有vector并且已经流行了30多年了,为什么还要再去使用那个array,而且vector还支持自动扩容等等,比array要方便太多,
因此,这个array容器属实是有些鸡肘了的。

不过非类型模板参数并非只有这一个使用场景,以后遇到我们再了解即可。


二、模板特化

通常情况下,使用模板可以实现很多与类型无关的代码,这确实提高了我们代码的复用性,但是在使用过程中我们会遇到一些特殊的数据类型,会带给我们意想不到的结果:

示例:

template<class T>
bool _less(const T& t1, const T& t2)
{
	return t1 < t2;
}

void Test_less()
{
	int a = 20;
	int b = 10;
	cout << _less(a, b) << endl;
	cout << _less(b, a) << endl;

	int* pa = &a;
	int* pb = &b;
	cout << _less(pa, pb) << endl;
	cout << _less(pb, pa) << endl;
}

运行实例:
在这里插入图片描述

此时就可以对模板进行特化:既在原模板类的基础上,针对特殊类型所进行的特殊化的实现方式
模板特化分为:函数模板特化和类模板特化

(一)函数模板特化

函数模板特化步骤:

  1. 必须要先有一个基础的函数模板;
  2. template后面跟一对空的尖括号
  3. 函数名后跟一对尖括号尖括号内指定特化类型
  4. 函数形参表:必须要和模板函数的基础参数类型完全相同。

补充:
在这里插入图片描述

对指针类型的特化:
在这里插入图片描述
当然,如果再有什么二级指针,我们就再特化一个二级指针的实例出来。

template<class T>
bool _less(T t1, T t2)
{
	return t1 < t2;
}

template<>
bool _less<int*>(int* t1, int* t2) // 1.1 特化一个 int*
{
	return *t1 < *t2;
}

bool _less(int* t1, int* t2)  //  1.2     直接写一个函数
{
	return *t1 < *t2;
}

template<typename T>
bool _less(T* t1, T* t2) //  2.1  写一个新的模板
{
	return *t1 < *t2;
}

void Test_less()
{
	int a = 20;
	int b = 10;
	cout << _less(a, b) << endl;
	cout << _less(b, a) << endl;

	int* pa = &a;
	int* pb = &b;
	cout << _less(pa, pb) << endl;
	cout << _less(pb, pa) << endl;
}


在这里插入图片描述

由此我们可以看出:特化在函数模板里的应用不仅使用不方便,而且效果也没有再写一个新的模板来的好,所以函数模板的特化很少使用。


(二)类模板特化

1.全特化

全特化:将模板参数列表里的所有模板全部确定化;

示例:


template<class T1, class T2>
class Print
{
public:
	void Output()
	{
		cout << "Print<T1, T2>" << endl;
	}
private:
	T1 _data1;
	T2 _data2;
};

template<>  
class Print<int, char>  //  T1,T2全部特化
{
public:
	void Output()
	{
		cout << "Print<int, char>" << endl;
	}
private:
	int _data1;
	char _data2;
};

void Test_Print1()
{
	Print<int, int>d1;
	d1.Output();

	Print<int, double>d2;
	d2.Output();

	Print<int, char>d3;
	d3.Output();
}

运行实例:
在这里插入图片描述


2.偏特化

偏特化分为两种形式:

  • 部分特化
template<class T1, class T2>
class Print
{
public:
	void Output()
	{
		cout << "Print<T1, T2>" << endl;
	}
private:
	T1 _data1;
	T2 _data2;
};

template<>
class Print<int, char>  // 全特化
{
public:
	void Output()
	{
		cout << "Print<int, char>" << endl;
	}
private:
	int _data1;
	char _data2;
};

template<class T1>
class Print<T1, char> //  特化第二个参数
{
public:
	void Output()
	{
		cout << "Print<T1, char>" << endl;
	}
private:
	T1 _data1;
	char _data2;
};

void Test_Print1()
{
	Print<int, int>d1;
	d1.Output();

	Print<int, double>d2;
	d2.Output();

	Print<int, char>d3;
	d3.Output();

	Print<char, char>d4;
	d4.Output();
}

在这里插入图片描述

  • 参数进一步限制
    特化不仅指上面的:将模板替换为确定了类型,也可以增加对模板类型的限制:如指定为指针或者引用等。

template<class T1, class T2>
class Print
{
public:
	void Output()
	{
		cout << "Print<T1, T2>" << endl;
	}
private:
	T1 _data1;
	T2 _data2;
};

template<class T1, class T2>
class Print<T1*, T2*>     //  T1,T2都特化为指针类型 -- 指针类型时走本特化模板
{
public:
	void Output()
	{
		cout << "Print<T1*, T2*>" << endl;
	}
private:
	T1 _data1;
	T2 _data2;
};

template<class T1, class T2>
class Print<T1&, T2&>     //  T1,T2都特化为引用类型 -- 引用类型时走本特化模板
{
public:
	void Output()
	{
		cout << "Print<T1&, T2&>" << endl;
	}
private:
	T1 _data1;
	T2 _data2;
};

void Test_Print2()
{
	Print<int, int>p1;
	p1.Output();

	Print<int*, int*>p2;
	p2.Output();

	Print<char*, char*>p3;
	p3.Output();

	Print<int**, int**>p4;
	p4.Output();

	Print<int&, int&>p5;
	p5.Output();
}

在这里插入图片描述

使用场景

template<class T>
class Greater
{
public:
	bool operator()(const T& e1, const T& e2)
	{
		return e1 > e2;
	}

};

void Test_sort()
{
	int a1 = 10;
	int a2 = 16;
	int a3 = 5;
	int a4 = 12;

	vector<int>a;
	a.push_back(a1);
	a.push_back(a2);
	a.push_back(a3);
	a.push_back(a4);

	sort(a.begin(), a.end());
	for (auto x : a)
		cout << x << ' ';
	cout << endl << endl;

	sort(a.begin(), a.end(), Greater<int>());  // 排降序
	for (auto x : a)
		cout << x << ' ';
	cout << endl << endl;
}

void Test_sort()
{
	int a1 = 10;
	int a2 = 16;
	int a3 = 5;
	int a4 = 12;

	vector<int*>pa;
	pa.push_back(&a1);
	pa.push_back(&a2);
	pa.push_back(&a3);
	pa.push_back(&a4);

	sort(pa.begin(), pa.end());
	for (auto x : pa)
		cout << *x << ' ';
	cout << endl << endl;

	sort(pa.begin(), pa.end(), Greater<int*>());
	for (auto x : pa)
		cout << *x << ' ';
	cout << endl << endl;
	
}

在这里插入图片描述

template<class T>
class Greater
{
public:
	bool operator()(const T& e1, const T& e2)
	{
		return e1 > e2;
	}

};

template<class T>
class Greater<T*>
{
public:
	bool operator()(T* e1, T* e2)
	{
		return *e1 > *e2;
	}

};

void Test_sort()
{
	int a1 = 10;
	int a2 = 16;
	int a3 = 5;
	int a4 = 12;

	vector<int*>pa;
	pa.push_back(&a1);
	pa.push_back(&a2);
	pa.push_back(&a3);
	pa.push_back(&a4);

	sort(pa.begin(), pa.end());
	//  	sort(pa.begin(), pa.end(), Less<int*>());  // 改进 -- 在写一个小于仿函数
	for (auto x : pa)
		cout << *x << ' ';
	cout << endl << endl;

	sort(pa.begin(), pa.end(), Greater<int*>());
	for (auto x : pa)
		cout << *x << ' ';
	cout << endl << endl;
	
}

在这里插入图片描述


三、模板分离编译

1. 什么是分离编译

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

2.模板的分离编译

在这里插入图片描述

我们上面的实现都是在Test.cpp里面进行的,上面写到一起就可以,我们应该都知道:标准情况下我们本就推荐函数声明和实现分离的,但是为什么这里分开就不行了呢?

下面我们一起来一探究竟:
首先,我们来更加详细地理一理分离编译的过程:预处理、编译、汇编、链接。
预处理阶段做什么工作?
— 头文件展开、条件编译、宏替换、以及注释清除;

编译阶段:
— 语法检查、生成汇编指令;

汇编阶段:
— 生成二进制代码;

链接阶段:
— 将多个目标文件链接称为单一的可执行文件。

在这里插入图片描述在这里插入图片描述

3.解决方法

  1. 在模板定义的位置显示实例化,(这种方法可以,但是使用麻烦,而且有时候会出问题,不推荐)。

在这里插入图片描述

  1. **将模板和定义放到一个文件中,如"xxx.hpp", 或者 “xxx.h”。**推荐这种。 在这里插入图片描述

四、模板总结

  • 优点
  1. 提高了代码的复用性,减少冗余,缩短了编程周期;
  2. 增强了代码的灵活性;
    这里的模板和之后的继承都是提高复用的很牛B的方法。
  • 缺点
  1. 模板会导致代码膨胀,导致编程时间变长(其实这不算缺点,因为如果不使用模板,我们就需要自己手写多份类似的代码,所以这些所谓的代码膨胀是必不可少的消耗);
  2. 出现模板编译错误时,提示信息非常凌乱,不易定位错误。(一有问题就会报一大堆错误 – 不过一般解决了最前面的几个就好了,这一点刚开始练习模板的朋友们会深有体会的)

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

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

相关文章

你知道多少接口性能优化的方案?

一、背景 针对老项目&#xff0c;去年做了许多降本增效的事情&#xff0c; 二、接口优化方案总结 1.批处理 批量思想&#xff1a;批量操作数据库&#xff0c;这个很好理解&#xff0c;我们在循环插入场景的接口中&#xff0c;可以在批处理执行完成后一次性插入或更新数据库…

Springboot的自动注入

一、开篇 在平时的开发过程中用的最多的莫属springboot了&#xff0c;都知道springboot中有自动注入的功能&#xff0c;在面试过程中也会问到自动注入&#xff0c;你知道自动注入是怎么回事吗&#xff0c;springboot是如何做到自动注入的&#xff0c;自动注入背后的原理是什么&…

基于 RocketMQ Connect 构建数据流转处理平台

作者&#xff1a;周波&#xff0c;阿里云智能高级开发工程师&#xff0c; Apache RocketMQ Committer 01 从问题中来的 RocketMQ Connect 在电商系统、金融系统及物流系统&#xff0c;我们经常可以看到 RocketMQ 的身影。原因不难理解&#xff0c;随着数字化转型范围的扩大及…

Linux学习笔记——多线程

文章目录补充知识Linux线程概念线程的优点线程的缺点线程异常线程用途多进程的应用场景Linux进程VS线程重新理解进程进程和线程线程共享的进程资源和环境为什么线程切换的成本更低进程和线程的关系Linux线程控制POSIX线程库创建线程线程ID及进程地址空间布局线程终止线程等待线…

pycharm常用的插件

pycharm等IDE 无法编辑bat文件 Chinese Language Pack 汉化插件 vim CodeGlance 右侧地图 将类似于Sublime中的代码小地图嵌入到编辑器窗格中。使用自定义颜色进行语法高亮&#xff0c;同时使用明暗主题。 Rainbow Brackets&#xff08;必备推荐&#xff09;收费了 这个插件…

【数据库原理 • 六】数据库备份与恢复

前言 数据库技术是计算机科学技术中发展最快&#xff0c;应用最广的技术之一&#xff0c;它是专门研究如何科学的组织和存储数据&#xff0c;如何高效地获取和处理数据的技术。它已成为各行各业存储数据、管理信息、共享资源和决策支持的最先进&#xff0c;最常用的技术。 当前…

Baumer工业相机堡盟工业相机中预处理相机的特性优势以及行业应用

Baumer工业相机堡盟工业相机如何通过BGAPISDK里显示彩色相机和黑白相机的图像&#xff08;C#&#xff09;Baumer工业相机Baumer工业相机的预处理相机的技术背景Baumer工业相机中预处理相机的特性Baumer工业相机中图像压缩相机的特性Baumer工业相机中3D激光相机的特性Baumer工业…

ESP32设备驱动-MAX30102脉搏血氧饱和度和心率监测传感器驱动

MAX30102脉搏血氧饱和度和心率监测传感器驱动 文章目录 MAX30102脉搏血氧饱和度和心率监测传感器驱动1、MAX30102介绍2、硬件准备3、软件准备4、驱动实现1、MAX30102介绍 MAX30102是一款集成脉搏血氧饱和度和心率监测生物传感器模块。 它包括内部 LED、光电探测器、光学元件和…

网页滚动体验,IScroll滚动插件,你安装了类似的滚动页面插件吗

IScroll是一款基于JavaScript的插件&#xff0c;用于在网页中实现平滑滚动效果。 这个插件可以帮助用户创建回到页面顶部和底部的按钮、生成页面导航快照&#xff0c;以及设置滚动时间等功能&#xff0c;从而提升网页的用户体验。 IScroll的特点在于&#xff0c;它能够平滑地…

【15】数据操作reshape、张量的运算

1. N维数组 ① 机器学习用的最多的是N维数组&#xff0c;N维数组是机器学习和神经网络的主要数据结构。 2. 创建数组 ① 创建数组需要&#xff1a;形状、数据类型、元素值。 3. 访问元素 ① 可以根据切片&#xff0c;或者间隔步长访问元素。 ② [::3,::2]是每隔3行、2列访问…

考研数据结构--线性表

线性表 文章目录线性表概述线性表的特点线性表的基本操作线性表的顺序表示概述优缺点操作顺序表的定义顺序表的初始化顺序表的插入顺序表的删除顺序表的查找顺序表的输出顺序表的判空顺序表的销毁main方法测试线性表的链式表示概述优缺点单链表操作单链表的定义单链表的初始化单…

自动化面试题3

1、PLC输入输出如何接线&#xff0c;源性漏型如何看&#xff1f; 所谓“源型输入”&#xff0c;是指电流从模块的公共端流入&#xff0c;从模块的输入通道流出的接线方式。源型输入的公共端作为电源正极&#xff08;共阳极&#xff09;。源型输入可以等效为在输入模块外部连接…

C# | 上位机开发新手指南(九)加密算法——RSA

上位机开发新手指南&#xff08;九&#xff09;加密算法——RSA 文章目录上位机开发新手指南&#xff08;九&#xff09;加密算法——RSA前言RSA的特性非对称性安全性可逆性签名速度较慢密钥管理RSA算法的参数公钥公钥指数e模数n私钥私钥指数d模数n质数p和qdp和dqqInv质数填充方…

性能测试,python 内存分析工具 -memray

Memray是一个由彭博社开发的、开源内存剖析器&#xff1b;开源一个多月&#xff0c;已经收获了超8.4k的star&#xff0c;是名副其实的明星项目。今天我们就给大家来推荐这款python内存分析神器。 Memray可以跟踪python代码、本机扩展模块和python解释器本身中内存分配&#xf…

yolov5-v7.0实例分割快速体验

简介 &#x1f680;yolov5-v7.0版本正式发布&#xff0c;本次更新的v7.0则是全面的大版本升级&#xff0c;最主要的功能就是全面集成支持了实例分割&#xff0c;yolov5已经集成检测、分类、分割任务。 前面几篇文章已经介绍过关于Yolov5的一些方面 yolov5目标检测:https://bl…

[计算机图形学]几何:曲线和曲面(前瞻预习/复习回顾)

一、曲线 1.Bzier Curves—贝塞尔曲线 贝塞尔曲线也是一种显式的几何表示方法。贝塞尔曲线定义了一系列的控制点&#xff0c;致使确定满足这些控制点关系的唯一一条曲线&#xff1a;如上图定义的贝塞尔曲线满足 起始点为p0&#xff0c;结束点为p3&#xff0c;起始点的切线方向…

ABB机械臂和RobotStudio编程简介

ABB机械臂和RobotStudio编程简介机械臂ABB机械臂ABB示教器RobotStudio与编程简介RobotStudio简介与安装RobotStudio使用RAPID程序指令机械臂 一种能够进行编程并在自动控制下执行某些操作和 移动作业任务的机械装置。 —— 美国国家标准局(NSB) 一种用于移动各种材料、零部件、…

基于目标级联法的微网群多主体分布式优化调度(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

家政服务小程序实战开发教程017-我的页面未注册功能开发

顾客在家政服务小程序可以在线提交预约信息&#xff0c;预约成功后可以查看订单的进度。我们本篇就来实现一下我的页面的功能。 1 新建页面 进入编辑器&#xff0c;在组件页面区域点击号&#xff0c;创建我的页面 2 未登录页面开发 我的页面的逻辑是如果用户未注册&#…

【MyBatisPlus】一文带你快速上手MyBatisPlus

文章目录MyBatisPlus学习笔记前言1、MyBatisPlus概述2、快速体验3、CRUD接口3.1 Mapper层CRUD接口3.1.1 Insert3.1.2 Delete3.1.3 Update3.1.4 Select3.2 Service层CRUD接口3.2.1 Save3.2.2 Remove3.2.3 Update3.2.4 Get3.3 自定义SQL接口4、常用注解和配置4.1 TableId4.2 Tabl…