c++初阶-------模板

server/2024/10/18 18:23:47/

作者前言

🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂
​🎂 作者介绍: 🎂🎂
🎂 🎉🎉🎉🎉🎉🎉🎉 🎂
🎂作者id:老秦包你会, 🎂
简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂
喜欢学习C语言、C++和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 🎂🎂🎂🎂🎂🎂🎂🎂
🎂个人主页::小小页面🎂
🎂gitee页面:秦大大🎂
🎂🎂🎂🎂🎂🎂🎂🎂
🎂 一个爱分享的小博主 欢迎小可爱们前来借鉴🎂


模板

  • **作者前言**
  • 类型分类
  • 非类型模板
  • array
  • 模板特化
    • 函数模板特化
    • 类模板特化
      • 全特化
      • 偏特化
        • 部分特化
        • 参数限制
  • 模板分离编译

类型分类

模板参数分类类型形参与非类型形参。
类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。
非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。
类型形参,这里就不过多介绍了

非类型模板

这个参数只能是整形常量

#include<iostream>
#include<vector>
#define N 10;
using namespace std;
namespace bit
{template<class T, size_t n>//之前的只能传类型,非类型只能传整形class AA {public:AA(){num = n;}void prit(){cout << num << endl;}private:size_t num;};
}
int main(){bit::AA<int,10> a;a.prit();return 0;
}

类型模板的只能传类型,而非类型模板可以传类型也可以传整形变量

array

这个容器就是非类型模板的
在这里插入图片描述
可以看出

模板特化

在原模板类的基础上,针对特殊类型所进行特殊化的实现方式。模板特化中分为函数模板特化类模板特化

函数模板特化

函数模板的特化步骤:

  1. 必须要先有一个基础的函数模板
  2. 关键字template后面接一对空的尖括号<>
  3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型,(参数类型和这个类型要一模一样)
  4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。
namespace bit
{//函数模板template<class T>bool less(const T&  a, const T& b){return a < b;}//函数特化template<>bool less<int>(const int& a, const int& b){return a < b;}
}
int main(){char  a = 20;char b = 10;cout << bit::less(a, b);return 0;
}

如果类型是特化后的类型,就走函数特化模板,否则就做走函数模板,
注意:函数模板必须有,特化后的函数,参数类型一定要对应函数模板的函数类型,否则会报错

类模板特化

同理,类模板特化的条件和函数特化的条件都是一样的, 只是类模板特化分为两类特化
一种是全参数特化,一种是部位参数特化

全特化

namespace bit
{//类模板template<class T, class Y>class AA{public:AA(const T& a, const Y& b){num1 = a;num1 = b;}private:T num1;Y num2;};template<>class AA<int, int>{public:AA(const int& a, const int& b){num1 = a;num1 = b;cout << " 我使用了全特化" << endl;}private:int num1;int  num2;};}int main(){bit::AA<int, int> funtion1(2, 2);bit::AA<int, char> funtion2(2, 2);return 0;
}

全特化,把所有的类模板参数都特化出类型, 然后使用

偏特化

偏特化有两个不一样的形式
一种是部位特化, 一种是类型的限定

部分特化
namespace bit
{//类模板template<class T, class Y>class AA{public:AA( T a,  Y b){num1 = a;num2 = b;cout << " 我使用了类模板" << endl;}private:T num1;Y num2;};template<class Y>class AA<int, Y> //规定类型必须是指针类型{typedef int  type;public:AA( type a,  Y b){num1 = a;num2 = b;cout << " 我使用了全特化" << endl;}private:type  num1;Y  num2;};}int main(){int a = 10;int b = 20;char c = 'a';bit::AA<int*, int*> funtion1(&a, &b);bit::AA<int, char*> funtion2(a, &c);return 0;
}

这种特化,只是特化一部分,一部分留下,可以更加灵活的使用

参数限制

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

namespace bit
{//类模板template<class T, class Y>class AA{public:AA( T a,  Y b){num1 = a;num2 = b;}private:T num1;Y num2;};template<class T, class Y>class AA<T*, Y*> //规定类型必须是指针类型{public:AA( T* a,  Y* b){num1 = a;num2 = b;cout << " 我使用了全特化" << endl;}private:const T* num1;const Y*  num2;};}int main(){int a = 10;int b = 20;char c = 'a';bit::AA<int*, int*> funtion1(&a, &b);bit::AA<int, char*> funtion2(a, &c);return 0;
}

在这里插入图片描述

还有一种写法,这种写法有许多坑,

namespace bit
{//类模板template<class T, class Y>class AA{public:AA( const T& a,  const Y& b){num1 = a;num2 = b;cout << " 我使用了类模板" << endl;}private:T num1;Y num2;};template<class T, class Y>class AA<T*, Y*> //规定类型必须是指针类型{public:AA( const T* const& a,  const T* const &  b){num1 = a;num2 = b;cout << " 我使用了全特化" << endl;}private:const T*  num1;const Y*  num2;};}

我们知道,传参会产生临时变量, 临时变量具有常性, 如果要引用, 需要const 修饰&
在这里插入图片描述

但是还是不建议使用,因为地址传递,引用用处不大

模板分离编译

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

假如有以下场景,模板的声明与定义分离开,在头文件中进行声明,源文件中完成定义:

test.h

#include<iostream>
#include<algorithm>
using namespace std;
namespace bit
{int Sub(int a, int b);template<class T>T Add(T a, T b);
}

test.cpp

namespace bit {template<class T>T Add(T a, T b){return a + b;}int Sub(int a, int b){return a - b;}
}

stack.cpp

#include"test.h"
int main()
{bit::Add<int>(1,2);cout << bit::Sub(3, 9);return 0;
}

当我们运行的时候,报错
在这里插入图片描述

原理:
在这里插入图片描述
函数在生成可执行程序的时候,sub函数的类型是确定的,而Add的函数里面的参数类型是不确定的,所以不会生成对应的指令

如果想要编译成功,就必须要清楚Add参数的类型,所以了一个方法**:显示实例化**
如图:
在这里插入图片描述
但是这个方法很局限,如果传入的参数是其他类型,又必须写一个对应显示实例化,所以说明了一个问题
模板函数声明和定义不要分离,就不用编译链接的时候去寻找了,同理类的定义和声明不能分离,尽量写在头文件里面


http://www.ppmy.cn/server/96391.html

相关文章

Docker常见命令

常见命令 # 启动docker systemctl start docker# 关闭docker systemctl stop docker # 重启docker systemctl restart docker# 查看docker运行状态 systemctl status docker# 设置docker开机启动 systemctl enable docker# 查看docker 版本 docker version# 查看docker守…

Radamsa:一款高性能通用模糊测试工具

关于Radamsa Radamsa是一款高性能的通用模糊测试工具&#xff0c;广大研究人员可以将其当作一个应用程序稳定性测试的测试用例生成工具。 工具运行机制 该工具使用简单&#xff0c;支持自定义脚本开发&#xff0c;可以用于测试程序对格式错误和潜在恶意输入的承受能力。它的工…

科普文:微服务之全文检索ElasticSearch 集成IK分词器

一、IK分词器简介 IKAnalyzer是一个开源的&#xff0c;基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始IKAnalyzer已经推出 了3个大版本。最初&#xff0c;它是以开源项目Lucene为应用主体的&#xff0c;结合词典分词和文法分析算法的中文分词组件。新版…

并查集问题

import java.util.HashMap; import java.util.List; import java.util.Stack;public class test33 {//由若干样本a、b、c、d……假设类型为V//在并查集中开始认为每个样本都在单独的集合里//用户可以在任何时候调用如下方法://1.boolean isSameSet(V x ,V y):查询样本x和样本y是…

强软弱虚四大引用

强引用&#xff1a; 如果一个对象具有强引用&#xff0c;垃圾回收器不会回收该对象&#xff0c;当内存空间不足时&#xff0c;JVM 宁愿抛出 OutOfMemoryError异常。 // 强引用 User usernew User();//user就是强引用软引用&#xff1a; 如果一个对象只具有软引用&#xff0…

信息安全专业好吗?

22 届的 211 信安毕业生&#xff0c;目前在读研&#xff08;虽然已经和安全没关系&#xff09;&#xff0c;整体来看大部分高校的信安都是作为计算机的附属专业存在的&#xff0c;除了极具特色的几个高校&#xff0c;例如山大的密码学&#xff0c;广州大学某院士加持的网络安全…

MongoDB 100问

基础问题 1. 什么是MongoDB&#xff1f; MongoDB是一种面向文档的NoSQL数据库&#xff0c;使用BSON&#xff08;二进制JSON&#xff09;格式存储数据。它支持动态模式设计&#xff0c;具有高性能、高可用性和易扩展性。 2. MongoDB和传统关系型数据库的区别是什么&#xff1f…

爬虫:xpath模块及昵图网实例

xpath模块 from lxml import etreestr1 """ <div><ul><li class"item-0"><a href"link1.html">first item</a></li><li class"item-1"><a href"link2.html">second…