C++模板进阶

目录

非类型模板参数

类模板的特化

分类

函数模板的特化

模板分离编译

问题

解决方法

1)不对模板定义进行分离或对模板进行特例化;

2)将声明和定义放在同一个文件

总结


关于C++模板的使用在《C++类和对象》中有介绍,本篇博客主要帮助读者对C++模板的一些特殊用法进行总结。

std::string的模拟实现-CSDN博客文章浏览阅读881次,点赞40次,收藏38次。通过模拟实现string可以帮助读者理解string成员函数的底层逻辑,让读者更准确地使用string中的成员函数。 https://blog.csdn.net/2401_87944878/article/details/145715615


非类型模板参数

模板参数分为两种:类型模板参数和非类型模板参数。

类型模板参数:跟在class和typename后的类型。

非类型模板参数:用一个常量作为参数,即不再使用class或typename来定义的参数。

template<class T,size_t N=10>
class Seqlist
{
public:private:T _arr[N];size_t size;
};

如上图所示:T是一个类型模板参数,用于替代各自类型;而N就是一个非类型模板参数,用于记录说要开辟的静态顺序表的大小,默认为10。

简而言之:就是有具体类型的参数就是非类型模板参数。

但是同样非类型模板参数也有一些要求:

1)参数应被当作常量使用。

2)参数类型必须是整形(bool,int,char,enum),指针,引用。(C++20添加了部分其他类型);


类模板的特化

在一些情况下,我们又是要对类的部分类型进行特殊化处理,即T在不同类型下,可能会出现不同的需求(函数实现),此时就需要引入类模板的特例化。

template<class T1,class T2>
class Date
{
public:
///
///   .....实现类成员函数
///
private:T1 _a;T2 _b;
};

上面代码是非特化模板,T1和T2可以表示任意类型。在编译阶段才去实例化为具体类型。

template<>
class Date<int, int>
{
public:
/// 
///  ......实现类成员函数
/// 
private:int _a;int _b;
};

以上代码是对Date类进行特例化,指明是<int ,int >类型。类模板特例化后相当于一个新的"类",但是这个类也不能脱离非特例化类独自出现,因为相当于新"类",所以需要自己再手动实现其功能(函数)

那么对于特例化模板参数和非特例化模板参数来说,编译器会对非特例化模板参数进行实例化来实现类???

实际上是不会的:如果会那我们对模板特例化就没有了意义,同时编译器已经识别了类型匹配,它会偷懒直接去掉现成的,而不是去耗时耗力的实例化。

Date<int, int> d1;   //去直接调用特例化的模板类
Date<char, int> d2;  //将模板参数实例化后调用

分类

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

都是字面意思:全特化就是全部模板参数都有指定;偏特化指的是部分模板参数被指定或者对某一类型进行限制。

//非特例化
template<class T1,class T2>
class test
{
public:private:T1 _a;T2 _b;
};

全特例化:不用给模板参数

//全特例化
template<>
class test<int, char>
{
public:private:int _a;char _b;
};

偏特例化:部分参数指定

//偏特例化
template<class T2>
class test<int,T2>
{
public:private:int _a;T2 _b;
};

偏特例化:对类型进行限制;

此处演示特例化为指针,也可以限制为引用...

//偏特例化:对类型进行限制
template<class T1, class T2>
class test<T1*,T2*>  //将其参数限制为指针
{
public:private:T1* _a;T2* _b;
};

当然也可以对类型进行混合限制。

//偏特例化:对类型进行限制
template<class T1, class T2>
class test<T1&, T2*>  //第一个参数限制为引用,第二个参数限制为指针
{
public:private:T1& _a;T2* _b;
};

 注意:以上代码的成员函数均没有写出,但是要知道的是:特化的类成员,类函数需要自己写来进行特殊化处理。


函数模板的特化

与类模板一样,函数模板也能进行特例化。

下面实现一个比较的函数。

template<class T>
bool Less(T x, T y)
{return x < y;
}

以上是实现一个各种类型的交换函数。但是当实参是指针的时候,比较就会比较的是指针的地址,这不是我们想要的结果,所以进行特化。

template<>
bool Less<int*>(int* x, int* y)
{return *x < *y;
}
template<class T>
bool Less(T* x, T* y)
{return *x < *y;
}

模板分离编译

问题

模板分离编译是一个很不推荐的写法,不提倡将函数的声明和定义分离到两个文件中去。

以下代码实现一个仿函数来实现小于比较。

"test.h"头文件

namespace less
{template<class T>class Less{public:bool operator()(T x,T y);};
}

test.cpp文件

template<class T>
bool less::Less<T>::operator()(T x, T y)
{return x < y;
}

main函数文件调用

using namespace less;
Less<int> less;
int a = 10;
int b = 33;
cout << less(a, b) << endl;

可以看到将类的函数的声明和定义分离,但是调用后却报错了。

可以看到此处运行时不是编译错误,而是连接错误,编译器没有找到指定的函数,为什么呢??

编译器没有找到函数意味着在test.cpp文件中函数的地址没有进入函数表。

原因在于:在编译期间,每个文件都是分开编译的,main函数中只包含头文件,检查语法时编译器在头文件中找到了仿函数的声明认为有这个函数,但是test.cpp文件中的仿函数是模板函数,相当于一个图纸,没有实例化所以不会在test,cpp函数表中生成函数地址,test.cpp文件函数表中也就没有仿函数地址,链接时就会报错了。

解决方法

1)不对模板定义进行分离或对模板进行特例化;

此处对上面代码中的模板进行特例化。

头文件显示实例化

template<class T>
class Less
{
public:bool operator()(T x,T y);
};template<>
class Less<int>
{
public:bool operator()(int x, int y);
};

test.cpp文件

bool less::Less<int>::operator()(int x, int y)
{return x < y;
}

2)将声明和定义放在同一个文件

在C++的库中,常常使用"xxxx.hpp"或"xxxx.h"文件来存放类模板函数的声明和定义。


 补充

typename和class的区别

typename和class都是模板类型的声明,在大多数情况下其没有本质区别,但是typename有指明类型的意思。以下是只能用typename的特例。

template<class T,class Container=deque<T>>
class Print
{
public:void test(){Container::const_iterator it = _con.begin();}private:Container _con;
};

以上代码,类成员函数test中定义了一个it的迭代器,看上去没有任何问题,但是编译时却报错了。

可以看到此处出现了语法错误,编译器无法确定Continer::const_iterator是什么。

为什么编译器无法判断其是什么呢???

原因:Container没有实例化所以编译器不知道这个容器里面定义了什么。那Container::a,其中a可以是什么???a可以是一个静态变量,一个内部类,也能是一种类型等等,编译器无法识别其具体是什么,所以此处需要指明其是类型,即添加typename的前缀。

typename Container::const_iterator it = _con.begin();

关于array

在C++中添加了一个数组的类array,实际上其与数组没有很大的区别,唯一的区别可能就是array比arr对于越界的检查更严格。


总结

模板既有优点也有缺点。

优点:1)模板服用代码,节省资源,更快的迭代开发;

           2)增强了代码的灵活性。

缺点:1)导致代码膨胀问题,编译时间增加;

           2)出错时,报错信息非常凌乱,不易定位错误位置。

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

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

相关文章

Ubuntu togo系统读写性能与原生系统测试

我前面把一个Ubuntu环境拷贝到了一个10Gbps的硬盘盒制作了一个Ubuntu togo的系统&#xff0c;帖子在这里&#xff0c;这篇文章主要用于测试使用Ubuntu togo的系统和原生系统的性能差异。 以下是测试Ubuntu togo系统与原系统性能差异的具体方案&#xff0c;结合移动硬盘特性及参…

【css酷炫效果】实现鱼群游动动态效果

【css酷炫效果】实现小鱼游动动态效果 缘创作背景css代码创建div容器引入jquery引入鱼群js完整代码效果图成品资源下载链接:点击下载 缘 在开发系统功能的时候,无意间看到了小鱼游动特效,感觉很有意思,就在网上找了相关教程,分享给大家。 创作背景 刚看到csdn出活动了…

停车场停车位数据集,标注停车位上是否有车,平均正确识别率99.5%,支持yolov5-11, coco json,darknet,xml格式标注

停车场停车位数据集&#xff0c;标注停车位上是否有车&#xff0c;平均正确识别率98.0&#xff05;&#xff0c;支持yolov5-11&#xff0c; coco json&#xff0c;darknet&#xff0c;xml格式标注 数据集-识别停车场所有车辆的数据集 数据集分割 一共184张图片 训练组 89&am…

结合基于标签置信度的特征选择方法用于部分多标签学习-简介版

假设 部分多标签学习&#xff08;PML&#xff09;假设&#xff1a;假设样本的标签集合中存在伪正标签&#xff0c;即某些标签可能是错误的。目标是从候选标签集中识别出真实标签。特征与标签的关系假设&#xff1a;假设不同的标签对应的特征子空间可能是不同的&#xff0c;而不…

Lora微LLAMA模型实战

引言 本文介绍如何复现Alpaca-lora&#xff0c;即基于alpaca数据集用lora方法微调Llama模型。 环境准备 实验环境用的是lanyun&#xff0c;新用户点击注册可以送算力。 下载huggingface上的模型是一个令人头疼的问题&#xff0c;但在lanyun上可以通过在终端运行source /etc…

Maven常见问题汇总

Maven刷新,本地仓库无法更新 现象 This failure was cached in the local repository and resolution is not reattempted until the update interval of aliyunmaven has elapsed or updates are forced原因 因为上一次尝试下载&#xff0c;发现对应的仓库没有这个maven配置…

什么是站群服务器?站群服务器应该怎么选?

站群服务器是专门用于托管和管理多个网站的服务器。通常用于SEO优化、内容分发、广告推广等场景&#xff0c;用户可以通过一个服务器管理多个站点&#xff0c;提升效率并降低成本。选择站群服务器时&#xff0c;需根据业务需求、性能要求、IP资源等因素进行综合考虑。 什么是站…

分享一个项目中遇到的一个算法题

需求背景&#xff1a; 需求是用户要创建一个任务计划在未来执行&#xff0c;要求在创建任务计划的时候判断选择的时间是否符合要求&#xff0c;否则不允许创建&#xff0c;创建的任务类型有两种&#xff0c;一种是单次&#xff0c;任务只执行一次&#xff1b;另一种是周期&…

【LInux进程六】命令行参数和环境变量

【LInux进程六】命令行参数和环境变量 1.main函数的两个参数2.利用main函数实现一个简单的计算器3.环境变量之一&#xff1a;PATH4.修改PATH5.在命令行解释器bash中查看所有环境变量6.用自己写的程序查看环境变量7.main函数的第三个参数8.本地的环境变量和环境变量9.环境变量具…

时间轴版本-2.0

文章简述 这是本人自己封装的时间轴2.0版本的代码&#xff0c;用到了TypeScriptJavaScript 这篇文章只有代码和具体的使用方式&#xff0c;如果想看具体的讲解可以参考本人写的时间轴1.0版本的&#xff0c;在1.0版本中可能计算时间线的逻辑略有不同&#xff0c;但是大致的计算…

大语言模型的压缩技术

尽管人们对越来越大的语言模型一直很感兴趣&#xff0c;但MistralAI 向我们表明&#xff0c;规模只是相对而言的&#xff0c;而对边缘计算日益增长的兴趣促使我们使用小型语言获得不错的结果。压缩技术提供了一种替代方法。在本文中&#xff0c;我将解释这些技术&#xff0c;并…

大华HTTP协议在智联视频超融合平台中的接入方法

一. 大华HTTP协议介绍 大华HTTP协议是大华股份&#xff08;Dahua Technology&#xff09;为其安防监控设备开发的一套基于HTTP/HTTPS的通信协议&#xff0c;主要用于设备与客户端&#xff08;如PC、手机、服务器&#xff09;之间的数据交互。该协议支持设备管理、视频流获取、…

Linux内核实时机制28 - RT调度器11 - RT 组调度

Linux内核实时机制28 - RT调度器11 - RT 组调度 相关数据结构 内核中通过static int sched_rt_runtime_exceeded(struct rt_rq *rt_rq)函数来判断实时任务运行时间是否超出带宽限制,判断这个运行队列rt_rq的运行时间是否超过了额定的运行时间。而“运行时间”和“额定时间”都…

java,poi,提取ppt文件中的文字内容

注意&#xff0c;不涉及图片处理。 先上pom依赖&#xff1a; <!-- 处理PPTX文件 --><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version></dependency><!--…

7、vue3做了什么

大佬认为有何优点&#xff1a; 组合式api----逻辑集中、对ts有更好的支持RFC–开放了一个讨论机制&#xff0c;可以看到每一个api的提案&#xff0c;方便源码维护&#xff0c;功能扩展&#xff0c;大家一起讨论 官方rfc响应式独立&#xff0c;new Proxy&#xff0c;天生自带来…

多人在线聊天系统,创建群,视频,语音,自带带授权码

多人在线聊天系统&#xff0c;创建群&#xff0c;视频&#xff0c;语音 带授权码&#xff0c;授权码限制 10 个网站&#xff0c;需要下载研究吧 在线聊天&#xff0c;创建群&#xff0c;表情&#xff0c;图片&#xff0c;文件&#xff0c;视频&#xff0c;语音&#xff0c;自…

数据结构概览

关键点&#xff1a; 数据结构是组织和存储数据的方式&#xff0c;帮助高效访问和操作数据。常见类型包括数组、链表、栈、队列、树和图&#xff0c;每种都有特定用途。代码示例和实际应用场景将帮助初学者理解这些概念。 什么是数据结构&#xff1f; 数据结构就像你整理书架或…

Android studio点击运行按钮在build\intermediates\apk\debug目录下生成的apk在真机上安装失败,提示test only

Android studio点击运行按钮在build\intermediates\apk\debug目录下生成的apk在真机上安装失败&#xff0c;提示test only DeepSeek R1 思考 15 秒 思考过程 针对Android Studio生成的APK在真机安装时提示“test only”的问题&#xff0c;以下是详细解决方案&#xff1a; 1.…

NFC 碰一碰发视频源码搭建,支持OEM

一、引言 NFC&#xff08;Near Field Communication&#xff09;近场通信技术&#xff0c;以其便捷、快速的数据交互特性&#xff0c;正广泛应用于各个领域。其中&#xff0c;NFC 碰一碰发视频这一应用场景&#xff0c;为用户带来了新颖且高效的视频分享体验。想象一下&#x…

Python基础语法全解析:从入门到实践

Python作为一门简洁高效、功能强大的编程语言&#xff0c;凭借其易读性和丰富的生态系统&#xff0c;已成为编程领域的“明星语言”。本文将系统讲解Python的核心语法&#xff0c;涵盖变量、数据类型、控制结构、函数、模块等核心概念&#xff0c;帮助读者快速掌握编程基础。 一…