【C++模板进阶】
目录
- 一、模板使用时的一个小注意点
- 二、非类型模板参数
- 三、类模板的特化
- 3.1函数模板的特化
- 3.2类模板的特化
- 3.2.1全特化
- 3.2.2偏特化
- 四、模板的分离编译
- 4.1模板不支持分离编译
- 4.2模板分离编译报错的分析
- 4.2解决方案
- 五、模板的总结
一、模板使用时的一个小注意点
在使用模板时,在有些场景下需要加上typename来告诉编译器这里是类型,否则会编译不通过。如:我想写一个不只是针对vector类型打印数据该怎么改写上面的代码呢?
#include<iostream>
using namespace std;#include<vector>void Print(const vector<int>& v)
{vector<int>::const_iterator it = v.begin();while (it != v.end()){cout << *it << " ";}cout<<endl;
}
int main()
{vector<int> v;v.push_back(10);v.push_back(20);v.push_back(30);v.push_back(40);v.push_back(50);Print(v);return 0;
}
首先对于泛型编程的思想一般都会考虑到用模板,所以一般我们都会这么改写代码。如:
#include<iostream>
using namespace std;#include<vector>
template<class Container>
void Print(const Container& v)
{Container::const_iterator it = v.begin();while (it != v.end()){cout << *it << " ";it++;}cout<<endl;
}
int main()
{vector<int> v;v.push_back(10);v.push_back(20);v.push_back(30);v.push_back(40);v.push_back(50);Print(v);return 0;
}
但是呢这种代码连编译都通过不了。如:
为什呢?
其实是编译器不知道Container::const_iterator
这个是类型还是对象
需要在前面加上typename告诉编译器这个是类型,等模板实例化后再去找。如:
二、非类型模板参数
假设有这样一个场景,我需要创建2个静态的顺序表。一个顺序表的容量是10个,另一个是1000个,该怎么玩呢?按照常规的方法肯定是玩不了的,这时就需要非类型模板参数了。可以这么玩。如:
namespace Ting
{template<class T,size_t N>class vector{private:T _arr[N];size_t capapcity;};
}int main()
{Ting::vector<int, 10> v1;Ting::vector<int, 1000> v2;return 0;
}
注意:
- 浮点数、类对象以及字符串是不允许作为非类型模板参数的。
- 非类型的模板参数必须在编译期就能确认结果且不能被修改。
三、类模板的特化
3.1函数模板的特化
直接先看代码,见一见猪跑。
//函数模板的特化
template<class T>
bool Less(T x, T y)
{return x < y;
}//对函数模板进行特化
template<>
bool Less<int*>(int* x, int* y)
{return *x < *y;
}
int main()
{int a = 2, b = 1;cout << Less(&a, &b) << endl;return 0;
}
乍一看是不是感觉函数模板特化有点与函数重载类似?感觉这个没啥用,但是这个是错觉。如:
//函数模板的特化
template<class T>
bool Less(T x, T y)
{return x < y;
}//对函数模板进行特化
template<class T>
bool Less(T* x, T* y)
{return *x < *y;
}
int main()
{int a = 2, b = 1;double c = 2.1, d = 2.2;cout << Less(&a, &b) << endl;cout << Less(&c, &d) << endl;return 0;
}
这种写法比函数重载要方便多了。
函数模板的特化步骤:
- 必须要先有一个基础的函数模板
- 关键字template后面接一对空的尖括号<>
- 函数名后跟一对尖括号,尖括号中指定需要特化的类型
- 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。
3.2类模板的特化
类模板的特化的步骤:
1.必须要有基础的类模板
2.关键字template后面接一对空的尖括号<>
3.类名后跟一对尖括号<>,尖括号中指定需要特化的类型。
类模板的特化分为:全特化和偏特化
3.2.1全特化
全特化即是将模板参数列表中所有的参数都确定化。
//函数模板的全特化
template<class T1,class T2>
class Ting
{
public:Ting(){cout << "Ting<T1,T2>" << endl;}
};
template<>
class Ting<int,char>
{
public:Ting(){cout << "Ting<int,char>" << endl;}
};
template<>
class Ting<double, char>
{
public:Ting(){cout << "Ting<double,char>" << endl;}
};int main()
{Ting<int, float> zft01;Ting<double, char> zft02;Ting<int, char> zft03;Ting<float, int> zft04;return 0;
}
3.2.2偏特化
//函数模板的偏特化
template<class T1, class T2>
class Ting
{
public:Ting(){cout << "Ting<T1,T2>" << endl;}
};template<class T1>
class Ting<T1,int>
{
public:Ting(){cout << "Ting<T1,int>" << endl;}
};template<class T1>
class Ting<T1, double>
{
public:Ting(){cout << "Ting<T1,double>" << endl;}
};//还可以对某种类型参数做进一步限制 如:
template<class T1,class T2>
class Ting<T1*,T2*>
{
public:Ting(){cout << "Ting<T1*,T2*>" << endl;}
};template<class T1, class T2>
class Ting<T1&, T2&>
{
public:Ting(){cout << "Ting<T1&,T2&>" << endl;}
};int main()
{return 0;
}
四、模板的分离编译
4.1模板不支持分离编译
比如有这样一个Add函数。如:
.h文件
#pragma once
template<class T>
T Add(T x, T y);
.cpp文件
#include"Add.h"template<class T>
T Add(T x, T y)
{return x + y;
}
测试文件
//模板的分离编译
#include"Add.h"
int main()
{cout << Add(1, 2) << endl;return 0;
}
运行时就会出现这样的报错。如:
4.2模板分离编译报错的分析
为什么会这样呢?
分析:
C/C++程序要运行,一般要经历一下步骤:
预处理—>编译—>汇编—>链接
编译:对程序按照语言特性进行词法、语法、语义分析,错误检查无误后生成汇编代码。注意头文件不参与编译,编译器对工程中的多个源文件是分离开单独编译的。
链接:将多个obj文件合成一个,并处理没有解决的地址问题。
4.2解决方案
第一种方法:显示实例化
.cpp文件
#include"Add.h"template<class T>
T Add(T x, T y)
{return x + y;
}//显示实例化
template
int Add(int x,int y);
int Add(double x, double y);
(以上的方法不推荐)
第二种方法:将声明和定义放到一个文件 “xxx.hpp” 里面或者xxx.h其实也是可以的。推荐使用这种。
五、模板的总结
【优点】
- 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
- 增强了代码的灵活性
【缺陷】 - 模板会导致代码膨胀问题,也会导致编译时间变长
- 出现模板编译错误时,错误信息非常凌乱,不易定位错误
相关文章:

【C++模板进阶】
目录 一、模板使用时的一个小注意点二、非类型模板参数三、类模板的特化3.1函数模板的特化3.2类模板的特化3.2.1全特化3.2.2偏特化 四、模板的分离编译4.1模板不支持分离编译4.2模板分离编译报错的分析4.2解决方案 五、模板的总结 一、模板使用时的一个小注意点 在使用模板时&…...

(一)RabbitMQ概念-优势、劣势、应用场景 、AMQP、工作原理
Lison <dreamlison163.com>, v1.0.0, 2023.06.22 RabbitMQ概念-优势、劣势、应用场景 、AMQP、工作原理 文章目录 RabbitMQ概念-优势、劣势、应用场景 、AMQP、工作原理RabbitMQ概念RabbitMQ的优势RabbitMQ劣势RabbitMQ应用的场景RabbitMQ_AMQPRabbitMQ工作原理 RabbitM…...

JetBrains全家桶:如何自定义实现类TODO注释?
文章目录 效果图具体方法参考文献 效果图 TODO注释大家应该都用过,在注释开头打上TODO的话,软件下方的TODO选项卡里就可以自动筛选出你打了TODO的注释,你可以点击里面对应的注释来实现快速跳转。 jetbrains全家桶(如Pycharm、Int…...

【技术干货】工业级BLE5.2蓝牙模块SKB378 使用教程,AT指令集
SKB378是一个高度集成的蓝牙5.2模组,可用来在2.4GHz ISM频段内做高速率、短距离无线通信。工业级标准,支持主从模式(1主对8从),支持串口透传,AT指令控制,且支持AoA蓝牙高精度室内定位,模组内部集成32位ARM …...

零基础深度学习——学习笔记1 (逻辑回归)
前言 因为各种各样的原因要开始学习深度学习了,跟着吴恩达老师的深度学习视频,自己总结一些知识点,以及学习中遇到的一些问题,以便记录学习轨迹以及以后复习使用,为了便于自己理解,我会将一些知识点用以个…...

I want to know on what switchport is connected my computer (10.8.0.2)
i.e. I am connected to an L2. I want to know on what switchport is connected my computer (10.8.0.2) Well….obviously not on this switch. Let’s dig Now I have the MAC address of my computer, we confinue to dig Computer has been seen on interface g0/2. Let’…...

OpenCv之人脸操作
目录 一、马赛克实现 二、人脸马赛克 三、人脸检测 四、多张人脸检测 一、马赛克实现 案例代码如下: import cv2 import numpy as npimg cv2.imread(8.jpg) # 马赛克方式一:缩小图片 # img2 cv2.resize(img,(600,400)) # # 马赛克方式二: # img2 cv2.resize(img,(600,4…...
C++[第五章]--指针和引用
指针和引用 文章目录 指针和引用1、引用2、指针3、右值引用4、引用限定符const和引用限定符1、引用 引用就是别名,引用定义时必须初始化: int a; int &b=a; //b即为a的别名 如果不是形参,必须初始化,引用某一变量 2、指针 指针和c一样; this指针 在类的成员函数中使…...

用i18next使你的应用国际化-React
ref: https://www.i18next.com/ i18next是一个用JavaScript编写的国际化框架。 i18next为您提供了一个完整的解决方案,本地化您的产品从web端到移动端和桌面端。 在react项目中安i18next依赖: i18nextreact-i18nexti18next-browser-languagedetector&…...

TSN -促进IT/OT 融合的网络技术
时间敏感网络(tsn)技术是IT/OT 融合的一项关键的基础网络技术,它实现了在一个异构网络中,实现OT的实时数据和IT系统的交互数据的带宽共享。 TSN允许将经典的高确定性现场总线系统和IT应用(如大数据传输)的功…...

改进的北方苍鹰算法优化BP神经网络---回归+分类两种案例
今天采用前作者自行改进的一个算法---融合正余弦和折射反向学习的北方苍鹰(SCNGO)优化算法优化BP神经网络。 文章一次性讲解两种案例,回归与分类。回归案例中,作者选用了一个经典的股票数据。分类案例中,选用的是公用的UCI数据集。 BP神经网络…...
等保工作如何和企业创新业务发展相结合,实现“安全”和“创新”的火花碰撞?
等保工作如何和企业创新业务发展相结合,实现“安全”和“创新”的火花碰撞?在当今数字化浪潮的背景下,企业越来越需要在“安全”和“创新”之间找到平衡点,以实现业务的持续创新和安全的有效保障。等保工作可以为企业提供安全保障…...
23.7.25 杭电暑期多校3部分题解
1005 - Out of Control 题目大意 解题思路 code 1009 - Operation Hope 题意、思路待补 code #include <bits/stdc.h> using namespace std; const int N 1e5 9; struct lol {int x, id;} e[3][N * 2]; int t, n, a[3][N * 2], hd[3], tl[3], vis[N * 2], q[N * …...

【设计模式——学习笔记】23种设计模式——桥接模式Bridge(原理讲解+应用场景介绍+案例介绍+Java代码实现)
问题引入 现在对不同手机类型的不同品牌实现操作编程(比如:开机、关机、上网,打电话等),如图 【对应类图】 【分析】 扩展性问题(类爆炸),如果我们再增加手机的样式(旋转式),就需要增加各个品牌手机的类,同样如果我们…...

文档翻译软件那么多,哪个能满足你的多语言需求?
想象一下,你手中拿着一份外文文件,上面记录着珍贵的知识和信息,但是语言的障碍让你无法领略其中的内容。而此时,一位翻译大师闪亮登场!他的翻译技巧犹如一把魔法笔,能够将文字的魅力和意境完美传递。无论是…...

MySQL 中NULL和空值的区别
MySQL 中NULL和空值的区别? 简介NULL也就是在字段中存储NULL值,空值也就是字段中存储空字符(’’)。区别 1、空值不占空间,NULL值占空间。当字段不为NULL时,也可以插入空值。 2、当使用 IS NOT NULL 或者 IS NULL 时࿰…...

阿里云容器镜像仓库(ACR)的创建和使用
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...

工业的相机与镜头(简单选型)
面阵相机,需要多大的分辨率?多少帧数? 前提条件: 1.被检测的物体大小 2.要求检测的精度是多少 3.物体是否在运动过程中进行检测,速度是多少 线阵相机选择(分辨率、扫描行数) 行频:每秒扫描多少行…...

numpy广播机制介绍
广播 广播机制的意义:广播描述了在算术运算期间NumPy如何处理具有不同形状的数组。受某些约束条件的限制,较小的数组会在较大的数组中“广播”,以便它们具有兼容的形状。 在对两个数组进行操作时,NumPy按元素对它们的形状进行比…...

RocketMQ 5.0 无状态实时性消费详解
作者:绍舒 背景 RocketMQ 5.0 版本引入了 Proxy 模块、无状态 pop 消费机制和 gRPC 协议等创新功能,同时还推出了一种全新的客户端类型:SimpleConsumer。 SimpleConsumer 客户端采用了无状态的 pop 机制,彻底解决了在客户端发布…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...

【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...