深入理解模板进阶:掌握C++模板的高级技巧

🎉个人名片:

🐼作者简介:一名乐于分享在学习道路上收获的大二在校生
🙈个人主页🎉:GOTXX
🐼个人WeChat:ILXOXVJE
🐼本文由GOTXX原创,首发CSDN🎉🎉🎉
🐵系列专栏:零基础学习C语言----- 数据结构的学习之路----C++的学习之路
🐓每日一句:如果没有特别幸运,那就请特别努力!🎉🎉🎉 ————————————————

🎉文章简介:

🎉本篇文章将 C++模板进阶,全特化,偏特化,非类型模板参数,模板的分离编译 相关知识进行分享!
💕如果您觉得文章不错,期待你的一键三连哦,你的鼓励是我创作动力的源泉,让我们一起加 油,一起奔跑,让我们顶峰相见!!!🎉🎉🎉
——————————————————

一.文章前言

上次将模初阶的学习知识进行了分享(链接: link),今天在这篇文章中你将学习到一些关于C++模板进阶的一些知识,包括模板特化和偏特化:介绍如何通过特化和偏特化来为特定类型提供定制化的模板实现,以及如何处理模板的重载和优先级问题。

二.模板

一. 非类型模板参数

首先,模板参数可以分为类类型形参和非类型形参

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

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

就比如:我们实现一个静态的栈的时候,定义一个静态数组,假设数组大小为N,N被#define为20,那么当我们想要实现一个大小为20的栈和一个大小为1000的栈时,只能被迫去改N的大小,但是如果改为1000的,栈空间为20的那个栈空间就会浪费,这个时候就可以使用非类型模板参数;

例如:

//假设实现一个静态栈
#define N 20
template<class T>
class stack
{
public:stack(){cout << "stack()" << endl;}
private:T _a[N];size_t _size;
};
int main()
{stack<int> stack1;   //20stack<int> stack2;   //100return 0;
}

解决方法:使用非类型模板参数

//使用非类型模板参数,整型常量
template<class T,size_t N>
class stack
{
public:stack(){cout << "stack()" << endl;}
private:T _a[N];size_t _size;
};
int main()
{stack<int,20> stack1;   //20stack<int,1000> stack2;   //1000return 0;
}

注意:
1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的。
2. 非类型的模板参数必须在编译期就能确认结果

例如:
在这里插入图片描述

二. 模板的特化

使用模板实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要进行特殊处理的方法;

例子:
//实现了一个日期类

class Date
{
public:Date(int year,int month,int day):_year(year),_month(month),_day(day){}bool operator>(Date& dd){if (_year > dd._year)return true;else if(_year == dd._year && _month > dd._month)return true;else if(_year == dd._year && _month == dd._month && _day > dd._day)return true;elsereturn false;}
private:int _year;int _month;int _day;
};

我们想要这样做比较时就会出错;

template<class T>
bool great(T x,T y)
{return x > y;
}
int main()
{Date d1(1010, 5, 3);Date d2(1010, 1, 2);cout << great(d1, d2)<< endl;Date* p1 = &d1;Date* p2 = &d2;   //当我们只有日期类对象的指针时,想要比较时cout << great(p1, p2) << endl;return 0;
}

解析:

如图:当我们调用函数1时,参数传的是一个日期类对象,T是一个日期类对象,当在>比较的时候,因为Date是自定义类型,就会去调用他的>运算符重载,实现比较。
但是当在调用第二个函数时,我们想的是对指针指向的对象进行比较,但是函数参数传的是Date的指针,great函数会实例化生成一个Date*的函数,去调用生成的函数,达不到想要的效果;
在这里插入图片描述

一.函数模板的特化

为了解决上面的问题:

1.我们可以使用仿函数类解决(仿函数在上篇分享过,不知道的可以去看看链接: link)

2.函数模板的实例化

template<class T>
bool great(T& x,T& y)
{return x > y;
}
//函数特化
template<>
bool great<Date*>(Date*& x, Date*& y)
{return *x > *y;
}

3.根据编译器的匹配机制再写一个函数即可这 ;

种实现简单明了,代码的可读性高,容易书写,因为对于一些参数类型复杂的函数模板,特化时特别给出,因此函数模板不建议特化。

template<class T>
bool great(T& x,T& y)
{return x > y;
}
//
bool great(Date* x, Date* y)
{return *x > *y;
}

类模板的特化

类模板的特化分为:全特化和偏特化

全特化

全特化:全特化即是将模板参数列表中所有的参数都确定化。

template<class T1, class T2>
class Data
{
public:Data() { }
private:T1 _d1;T2 _d2;
};//特化后
template<>
class Data<int, char>
{
public:Data() { }
private:int _d1;char _d2;
};
void test()
{Data<int, int> d1;   //调用原模版Data<int, char> d2;   //调用特化后的
}
偏特化

偏特化:任何针对模版参数进一步进行条件限制设计的特化版本

偏特化也有两种:
第一种:部分特化
将模板参数列表中部分特化

//原模版
template<class T1, class T2>
class Data
{
public:Data() { }
private:T1 _d1;T2 _d2;
};
//特化后
template<class T1>
class Data<T1,char>
{
public:Data(){ }
private:T1 _d1;char _d2;
};

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

例如下面的例子,特化后只能接受指针类型;

//原模版
template<class T1, class T2>
class Data
{
public:Data() { }
private:T1 _d1;T2 _d2;
};
//特化后
template<class T1,class T2>
class Data<T1*,T2*>
{
public:Data() { }
private:T1 _d1;T2 _d2;
};

三. 模板的分离编译

什么是分离编译?

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

当我们写一个函数模板时,.h放声明,.cpp放定义时,例如:

在这里插入图片描述

最后编译器会报链接错误;

这是因为:
C/C++程序要运行,一般会经历预处理–>编译–>汇编–>链接这四个步骤,

预处理:
主要是头文件的展开,这里的话Test.h,会在main.cpp与Test.cpp里面展开,生成main.i与Test.i,因为头文件展开了,就没有头文件了;
展开了过后Test.i里面既有函数声明也有函数定义;main.i里面有函数声明,没有定义;

编译:
检查语法,实例化模板等操作,如果没有错误后会形成汇编代码;生成main.s与Test.s;实例化模板的时候,这里不知道实例化为什么类型的函数没所以这里并没有实例化函数;

汇编:
生成二进制的机器语言;生成mian.o与Test.o

链接:会将这两个文件合并到一起,到这里会发现函数找不到函数的地址,这两个文件前面3不都是分离的,没有交互,mian.i里面知道将func函数模板中T实例化为int,但是没有函数的定义,只有声明,Test.i可以实例化生成函数,但是不知道将T实例化为什么类型,所以到最后的合并后,没有函数地址,报链接错误;

最好的解决方法,函数模板就不要声明定义分离;

请添加图片描述

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

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

相关文章

分析基于解析物理模型的E模式p沟道GaN高电子迁移率晶体管(H-FETs)

来源&#xff1a;Analyzing E-Mode p-Channel GaN H-FETs Using an Analytic Physics-Based Compact Mode&#xff08;TED 24年&#xff09; 摘要 随着近期对用于GaN互补技术集成电路&#xff08;ICs&#xff09;开发的p沟道GaN器件研究兴趣的激增&#xff0c;一套全面的模型…

ssh免密登陆更换目标主机后无法连接

在进行hadoop分布式环境搭建时&#xff08;三台机&#xff0c;master&#xff0c;slave1&#xff0c;slave2&#xff09;&#xff0c;后期slave2系统出现问题&#xff0c;更换新机后&#xff0c;master与slave2文件传输失败&#xff1a; 以为是秘钥过期的问题&#xff0c;更换…

【C语言】C语言内存函数

&#x1f451;个人主页&#xff1a;啊Q闻 &#x1f387;收录专栏&#xff1a;《C语言》 &#x1f389;道阻且长&#xff0c;行则将至 前言 这篇博客是关于C语言内存函数(memcpy,memmove,memset,memcmp)的使用以及部分的模拟实现 memcpy,memmove,memset,memc…

DHCP在企业网的部署及安全防范

学习目标&#xff1a; 1. DHCP能够解决什么问题&#xff1f; 2. DHCP服务器如何部署&#xff1f; 3. 私接设备会带来什么问题以及如何防范&#xff1f; 给DHCP服务器配置地址&#xff1a; 地址池&#xff1a; DHCP有2种分配模式&#xff1a;全局分配和接口分配 DHCP enable

Unity在UGUI上通过绘制网格顶点自由画线

该插件的实现是使用UI组件的绘图API来动态生成和修改几何形状&#xff0c;可自由动态更改画线的粗细、拐角圆滑度、颜色&#xff0c;自由增减节点&#xff0c;不额外增加gameobject&#xff0c;并且在原生的UGUI上以ScreenSpace-Overlay的状态下&#xff0c;显示效果如下所示 …

Vue2(七):超详细vue开发环境搭建(win7),nodejs下载与安装,安装淘宝镜像(报错已解决),配置脚手架

一、安装node.js 本来想粗略写一下的&#xff0c;但是搭建脚手架的时候&#xff0c;遇到了很多问题&#xff0c;浪费快两天时间&#xff0c;记录一下自己的解决办法希望对你们有帮助&#xff01; 1.下载nodejs 安装包下载链接【CNPM Binaries Mirror】 下载我划线的这个&am…

HTML案例-1.标签练习

效果 源码 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head&g…

蓝桥杯-Sticks-DFS搜索

题目 样例输出是 6 5 题目中给错了&#xff0c;不知道什么时候会改。 思路 --剪枝&#xff0c;否则时间复杂度和空间复杂度过大&#xff0c;会超时。 --注意有多组测试样例时&#xff0c;需要将bool数组重新赋值为false。 --函数类型不是void&#xff0c;return语句不能省…

Wmware安装Linux(centerOS、Ubuntu版本)

目录 1、安装wmware 2、center版本 3、ubuntu版本 1、安装wmware 此处不做展开。 2、center版本 需要提前下载的文件&#xff1a; 无图形化界面https://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso 有图形化界面https://mirrors.a…

论文阅读——Vision Transformer with Deformable Attention

Vision Transformer with Deformable Attention 多头自注意力公式化为&#xff1a; 第l层transformer模块公式化为&#xff1a; 在Transformer模型中简单地实现DCN是一个non-trivial的问题。在DCN中&#xff0c;特征图上的每个元素都单独学习其偏移&#xff0c;其中HWC特征图上…

爱恩斯坦棋小游戏使用C语言+ege/easyx实现

目录 1、游戏介绍和规则 2、需要用到的头文件 3、这里我也配上一个ege和easyx的下载链接吧&#xff0c;应该下一个就可以 4、运行结果部分展示 5、需要用到的图片要放在代码同一文件夹下 6、代码地址&#xff08;里面有需要用到的图片&#xff09; 1、游戏介绍和规则 规则如…

C++ Qt开发:QUdpSocket网络通信组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍如何运用QUdpSocket组件实现基于UDP的网络通信…

Windows server 2008 R2 在VMware虚拟机上的安装

Windows server 2008 R2 在VMware虚拟机上的安装 准备工作VMware 新建并配置虚拟机安装和启动Windows server 2008 R2 准备工作 Windows server 2008 R2 ISO镜像的下载&#xff1a;Windows server 2008 R2 ISO VMware 新建并配置虚拟机 第一步&#xff0c;点击新建虚拟机 第…

sqllab第二十关通关笔记

知识点&#xff1a; cookie注入 可以进行url解析错误注入传参位置 get请求post请求cookie传参 输入admin admin进行登录&#xff0c;抓取当前数据包 通过放包发现是一个302跳转的响应包&#xff0c;页面只有一个 I Love Cookies&#xff1b;没什么信息 通过点击页面上方的按钮…

3.Gen<I>Cam文件配置

Gen<I>Cam踩坑指南 我使用的是大恒usb相机&#xff0c;第一步到其官网下载大恒软件安装包,安装完成后图标如图所示&#xff0c;之后连接相机&#xff0c;打开软件&#xff0c;相机显示一切正常。之后查看软件的安装目录如图&#xff0c;发现有GenICam和GenTL两个文件&am…

智能ai文生视频,文生动漫小程序,系统搭建开发

目录 前言&#xff1a; 一、文生动漫系统搭建常规步骤 二、文生漫画是怎么操作的 总结&#xff1a; 前言&#xff1a; 小说推文是继短视频之后的又一个黄金赛道&#xff0c;它最大的特点就是&#xff0c;有一个人观看了你推荐的小说就有一份收益。那么使用系统小说转漫功能…

如何选择合适的数据可视化工具?

如果是入门级的数据可视化工具&#xff0c;使用Excel插件就足够了&#xff01; Excel插件&#xff0c;tusimpleBI 是一款 Excel 图表插件&#xff0c;提供超过120项图表功能&#xff0c;帮助用户制作各种 Excel 所没有的高级图表&#xff0c;轻轻松松一键出图。 它能够制作10…

《计算机视觉中的深度学习》之目标检测算法原理

参考&#xff1a;《计算机视觉中的深度学习》 概述 目标检测的挑战&#xff1a; 减少目标定位的准确度减少背景干扰提高目标定位的准确度 目标检测系统常用评价指标&#xff1a;检测速度和精度 提高精度&#xff1a;有效排除背景&#xff0c;光照和噪声的影响 提高检测速度…

D咖自助咖啡机:颠覆传统,重塑咖啡体验?

在咖啡文化日益蓬勃发展的今天&#xff0c;传统的咖啡消费方式已经不能完全满足人们对于咖啡品质和体验的追求。在这个背景下&#xff0c;商用自助咖啡机以其独特的优势和创新&#xff0c;正在颠覆传统的咖啡消费模式&#xff0c;为咖啡爱好者们打开了全新的咖啡体验之门。D咖今…

多模态:Vary-toy

文章目录 前言一、模型结构二、数据工程总结 前言 Vary的提出让大模型在OCR相关任务的能力有了很大突破&#xff0c;通过提出额外的视觉词汇表模块来弥补单一CLIP编码能力的不足&#xff0c;详情可参考我之前的文章——多模态&#xff1a;Vary。 最近Vary的团队开发了一个更小…