【C++】--------模板进阶

目录

前言

一、非类型模板参数

定义

二、模板的特化(步骤都一样)

1.概念

2.函数模板特化的步骤

3.类模板的特化

3.1全特化

3.2偏特化/半特化

三、模板的分离与编译

1.什么是分离编译?

2.模板的分离与编译

四、总结


前言

我们已经有浅谈了模板,大概了解什么是泛型编程、函数模板以及类模板的相关内容,同时在前面的几个容器的模拟实现中,我们也是用到大量模板的知识,但是那只是开始,接下来我们来看看模板还有哪些值得我们去了解与体会的地方!

一、非类型模板参数

这里我们需要在回顾一下函数参数与类型模板参数

  • 函数参数

函数参数中的参数是对象,形如:

函数(T 对象1,T 对象2);
  • 模板参数

模板的参数是类型,也叫类型模板参数,形如:

模板(class 类型1,……);

定义

那么什么是非类型模板参数呢?顾名思义,就是用一个常量作为类(函数)模板中的一个参数,在类(函数)模板中可以将该参数当成常量来使用!

形如:

//类型+常量
template<class T, size_t N = 10>
class A
{
    
    private:
        T a[N];//用来定义一个模板类型的静态数组
};

注意:

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

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

二、模板的特化(步骤都一样)

1.概念

  • 通常情况下, 使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结 ,需要特殊处理!
  • 本质就是针对某些特殊类型进行特殊化处理时,可以使用特化,比如Date类型,指针,引用等等
  • 需要注意,特化应该要先有一个基础的模板!

2.函数模板特化的步骤

  • 必须先有一个基础的模板!

比如:

// 基础的函数模板 -- 参数匹配
template<class T>
bool Mgreater(T left, T right)
{
 return left > right;
}


如果T是指针呢?用该模板比较会出错,比的只是指针,而不是指针的内容!
  • 关键字template后面接一对空的尖括号<>
  • 函数名后跟一对尖括号,尖括号中指定需要特化的类型( 这个尖括号可有可无
  • 函数形参表必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。
    //对Mgreater函数的特化
    template<>
    bool Mgreater(Date* left, Date* right)
    {
        return *left>*right;
        
    }
    
    int main()
    {
       	Date* p1 = new Date(2022, 7, 7);
    	Date* p2 = new Date(2022, 7, 8);
    	cout << Less(p1, p2) << endl;  //比较两个日期的大小,而不是指针的大小
    }

    需要注意:一般情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都是将该函数直接给 出。

    比如:

    //对Mgreater函数的特化
    bool Mgreater(Date* left, Date* right)
    {
        return *left>*right;
        
    }
    
    int main()
    {
       	Date* p1 = new Date(2022, 7, 7);
    	Date* p2 = new Date(2022, 7, 8);
    	cout << Less(p1, p2) << endl;  //比较指针的内容(日期大小),而不是指针本身
    }

    其他特化样例:

    //指针
    template<class T>
    bool Mgreater(T* left, T* right)
    {
    	return *left > *right;
    }

    实际上我们不建议函数模板进行特化,这样看起来很复杂,对于一些复杂的类型,特别给出即可!

    3.类模板的特化

    3.1全特化

    • 将所有参数都确定化
    // 基础类模板
    template<class T1, class T2>
    class Data
    {
    public:
    	Data() { cout << "Data<T1, T2>" << endl; }
    private:
    	T1 _d1;
    	T2 _d2;
    };
    
    
    //全特化模板
    template<>
    class Data<int,char>//确定为指定的类型
    {
    public:
    	Data() { cout << "Data<T1, T2>" << endl; }
    private:
    	T1 _d1;
    	T2 _d2;
    };
    
    int main()
    {
        Data<int,char> a;
        return 0;
    }

    3.2偏特化/半特化

    • 部分特化(将参数列表中的一部分参数进行特化)
    //部分特化,部分参数的类型已经定死,char定死了
    template<class T>
    class Data<T,char>//
    {
    public:
    	Data() { cout << "Data<T1, T2>" << endl; }
    private:
    	T1 _d1;
    	T2 _d2;
    };
    • 对参数进行更近一步的限制
    //更进一步限制,两种都是不确定的类型,但是又是指定的类型
    //T是不确定的,但是T*是确定的,就是只能是任意类型的指针
    template<class T1,class T2>
    class Data<T1*,T2*>//
    {
    public:
    	Data() { cout << "Data<T1, T2>" << endl; }
    private:
    	T1 _d1;
    	T2 _d2;
    };
    
    
    //引用+指针
    template<class T1,class T2>
    class Data<T1&,T2*>//
    {
    public:
    	Data() { cout << "Data<T1, T2>" << endl; }
    private:
    	T1 _d1;
    	T2 _d2;
    };
    
    
    //引用
    template<class T1,class T2>
    class Data<T1&,T2&>//
    {
    public:
    	Data() { cout << "Data<T1, T2>" << endl; }
    private:
    	T1 _d1;
    	T2 _d2;
    };
    
    
    int main()
    {
        Data<int&, string*> d7;//调用特化的指针版本
        Data<int*,char*> d8;//调用特化的引用指针版本
        Data<int&,char&> d9;//调用特化的引用版本
    }
    
    

三、模板的分离与编译

1.什么是分离编译?

        一个程序由若干个源文件共同实现,每个源文件各自进行编译生成目标文件最后将所有目标文件链接起来形成单一的可执行文件的过程!

2.模板的分离与编译

看代码:

// a.h,声明Add函数
template<class T>
T Add(const T& left, const T& right);


// a.cpp,定义Add函数
#include "a.h"
template<class T>
T Add(const T& left, const T& right)
{
 return left + right;
}


//test.cpp,调用Add函数
#include "a.h"

int main()
{
    Add(1,2);
    return 0;
}

//能否成功编译?

现象:

这是一段链接错误的警告,其实就是调用的地方找不到函数的地址

原因:在编译时,头文件会展开,因此在调用Add函数的地方才知道T是什么类型的,但是呢在调用的地方只是包含了声明,没有定义,而定义的地方(Add.cpp)却不知道T是什么类型,那就没有办法去实例化出一个具体的代码,那就不会形成地址,那就没有链接的地方,call不了Add,所以会链接报错!

解决方案:

①在定义的位置显示实例化----->不推荐使用,因为一旦换了类型,又得在显示写一个实例化

②声明和定义放在一起--------->推荐使用

为何呢?

因为.h预处理展开后,实例化模板时,既有声明也有定义,直接就实例化,编译时,有函数的定义,直接就有地址,不需要链接时再去找!

所以模板不能最好不要声明和定义分开!

四、总结

【优点】
1. 模板复用了代码,节省资源,更快的迭代开发, C++ 的标准模板库 (STL) 因此而产生
2. 增强了代码的灵活性
【缺陷】
1. 模板会导致代码膨胀问题,也会导致编译时间变长
2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误

今天的分享就到这里!谢谢你的阅读!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

BPE、Wordpiece、Unigram、SpanBERT等Tokenizer细节总结

BPE(Byte Pair Encoding) GPT-2和Roberta用的是这种&#xff0c;不会产生[UNK]这个unknown字符 这部分部分摘录自https://martinlwx.github.io/zh-cn/the-bpe-tokenizer/ 看以下code例子就足够理解了&#xff0c;核心是维护self.merges&#xff08;维护一个pair->str的字…

一文掌握Vue依赖注入:原理、应用场景以及最佳模块化与单元测试实践,提升代码的可维护性与模块化程度

Vue 中的依赖注入&#xff08;Dependency Injection, DI&#xff09;机制通过 provide 与 inject API&#xff0c;实现了跨组件层级间的数据与服务透明传递&#xff0c;使父组件能够向其任意深度的子孙组件“注入”依赖&#xff0c;而不需要通过层层传递 props 或使用全局状态管…

Pytorch实现线性回归模型

在机器学习和深度学习的世界中&#xff0c;线性回归模型是一种基础且广泛使用的算法&#xff0c;简单易于理解&#xff0c;但功能强大&#xff0c;可以作为更复杂模型的基础。使用PyTorch实现线性回归模型不仅可以帮助初学者理解模型的基本概念&#xff0c;还可以为进一步探索更…

SpringCloud(微服务介绍,远程调用RestTemplate,注册中心Nacos,负载均衡Ribbon,环境隔离,进程和线程的区别)【详解】

目录 一、微服务介绍 1. 系统架构的演变 1 单体架构 2 分布式服务 3 微服务 2. SpringCloud介绍 SpringCloud简介 SpringCloud版本 3. 小结 二、远程调用RestTemplate【理解】 1. 服务拆分 1 服务拆分原则 2 服务拆分示例 1) 创建父工程 2) 准备用户服务 1. 用户…

Docker数据管理与Dockerfile镜像创建

前言 在容器化环境中&#xff0c;如何有效地管理和持久化数据成为了开发人员和运维团队面临的挑战之一&#xff1b;另一方面&#xff0c;镜像的创建是构建容器化应用的基础。优化的镜像设计可以提高部署效率和应用性能&#xff0c;减少资源消耗和运行成本。本文将介绍 Docker …

锂电池SOH预测 | 基于LSTM的锂电池SOH预测(附matlab完整源码)

锂电池SOH预测 锂电池SOH预测完整代码锂电池SOH预测 锂电池的SOH(状态健康度)预测是一项重要的任务,它可以帮助确定电池的健康状况和剩余寿命,从而优化电池的使用和维护策略。 SOH预测可以通过多种方法实现,其中一些常用的方法包括: 容量衰减法:通过监测电池的容量衰减…

锂电池SOH预测 | 基于CNN-GRU的锂电池SOH预测(matlab)

锂电池SOH预测 锂电池SOH预测完整代码锂电池SOH预测 锂电池的SOH(状态健康度)预测是一项重要的任务,它可以帮助确定电池的健康状况和剩余寿命,从而优化电池的使用和维护策略。 SOH预测可以通过多种方法实现,其中一些常用的方法包括: 容量衰减法:通过监测电池的容量衰减…

【Docker】Docker 实践(三):使用 Dockerfile 文件构建镜像

Docker 实践&#xff08;三&#xff09;&#xff1a;使用 Dockerfile 文件构建镜像 1.使用 Dockerfile 文件构建镜像2.Dockerfile 文件详解 1.使用 Dockerfile 文件构建镜像 Dockerfile 是一个文本文件&#xff0c;其中包含了一条条的指令&#xff0c;每一条指令都用于构建镜像…

解决VMware启动异常

问题1&#xff1a;该虚拟机似乎正在使用中。如果该虚拟机未在使用&#xff0c;请按“获取所有权(T)”按钮获 取它的所有权。否则&#xff0c;请按“取消(C)”按钮以防损坏。 解决步骤&#xff1a; 按弹框提示的配置文件目录下删除后缀为lck的文件&#xff08;lock&#xff09;。…

Facebook的未知力量:数字世界的新引擎

在数字化的时代&#xff0c;社交媒体已经成为了我们日常生活中不可或缺的一部分&#xff0c;而Facebook作为其中的巨头&#xff0c;其影响力远远超出了我们的想象。但是&#xff0c;Facebook背后隐藏的力量和影响远不止于此&#xff0c;它正逐渐成为数字世界的新引擎&#xff0…

C语言-动态内存分配

即使行动导致错误&#xff0c;却也带来了学习与成长;不行动则是停滞与萎缩。&#x1f493;&#x1f493;&#x1f493; •&#x1f319;知识回顾 亲爱的友友们大家好&#xff01;&#x1f496;&#x1f496;&#x1f496;&#xff0c;我们紧接着要进入一个新的内容&#xff0c;…

STM32单片机C语言模块化编程实战:按键控制LED灯详解与示例

一、开发环境 硬件&#xff1a;正点原子探索者 V3 STM32F407 开发板 单片机&#xff1a;STM32F407ZGT6 Keil版本&#xff1a;5.32 STM32CubeMX版本&#xff1a;6.9.2 STM32Cube MCU Packges版本&#xff1a;STM32F4 V1.27.1 之前介绍了很多关于点灯的方法&#xff0c;比如…

微信小程序的常用API②

一、动画API &#xff08;1&#xff09;作用&#xff1a;用于在微信小程序中完成动画效果的制作 &#xff08;2&#xff09;使用&#xff1a;创建实例 wx.createAnimation() &#xff08;3&#xff09;常用属性&#xff1a; duration 【number型】 动画持续时间&…

Qt的qtmqtt库连接onenet出现QMQTT::SocketRemoteHostClosedError解决方法

问题描述 在Qt发开过程中使用qtmqtt库来连接onenet的mqtt服务器&#xff0c;在ClientId、Username和Password均填写正确的情况下还是连接不上&#xff0c;查看错误显示QMQTT::SocketRemoteHostClosedError。 解决方法 client中的CleanSession标志位必须设置为true。 client …

分子动力学模拟学习-Gromacs工具链

1、总体流程 在gromacs的使用说明中有一个flow chart&#xff0c;比较简略。以下针对一般体系&#xff08;非蛋白等领域&#xff09;进行了一些调整&#xff0c;通用性更强。 在做分子动力学模拟时&#xff0c;其复杂性除了以上各种输入输出文件的操作&#xff0c;另一点就是力…

眼图仪参数理解和一些测量指标

参考资料&#xff1a; https://www.eet-china.com/mp/a35960.html 一&#xff1a;关于眼图仪&#xff1a; :::warning ●如果追溯历史&#xff0c;大约47年前&#xff0c;眼图就已经开始广泛应用。在1962年-2002的40年间&#xff0c;眼图的测量方法是基于采样示波器的传统方法…

3GPP相关资料收集整理

1、3GPP介绍 主页&#xff1a;3GPP – The Mobile Broadband Standard 3GPP(3rd Generation Partnership Project,第三代合作伙伴计划)成立于1998年12月&#xff0c;多个电信标准组织伙伴共同签署了《第三代伙伴计划协议》。3GPP最初的工作范围是为第三代移动通信系统制定全球适…

IDEA实现Springboot项目自动热部署

每当我们在修改代码时&#xff0c;往往需要重新启动项目&#xff0c;这样不仅浪费时间而且很麻烦&#xff0c;我们可以通过IDEA的热部署来提高效率 1、首先点file >> settings >> Build Excution >> Compire&#xff0c;选择Build project auto matically 2.…

linux kernel内存泄漏检测工具之slub debug

一、背景 slub debug 是一个debug集&#xff0c;聚焦于kmem_cache 分配机制的slub内存&#xff08;比如kmalloc&#xff09;&#xff0c;这部分内存在内核中使用最频繁&#xff0c;slub debug其中有相当部分是用来处理内存踩踏&#xff0c;内存use after free 等异常的&#x…

虚良SEO多口子权重蜘蛛池怎么正确使用

一、蜘蛛池的工作原理 蜘蛛池的核心在于通过大量的页面和内容&#xff0c;提高网站的搜索引擎排名&#xff0c;从而获得更多的流量和曝光机会。这种策略通常被用于网站推广和SEO优化。通过将网站链接发布到蜘蛛池中&#xff0c;可以增加网站的曝光率&#xff0c;吸引更多的搜索…
最新文章