模板进阶(C++)

news2024/9/27 5:57:23

一.非类型模板参数

1.使用方法和概念

模板参数分为类型形参非类型形参

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

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

注意:在c++20之前,这个常量只允许是像(int,size_t,long long……)这样的整数类型,在c++20之后开始支持浮点类型

2.应用

定义静态数组

namespace bite
{
 // 定义一个模板类型的静态数组
 template<class T, size_t N = 10>
 class array
 {
     private:
     T _array[N];
     size_t _size;
 };
}

注意:静态数组只能用这种方式封装,在构造函数传参是不行的——那只能是动态内存管理。

3.非类型模板参数在STL中的应用–array类

实现原理与上面的应用是一样的。

3.1 array的优点

1. 普通的静态数组越界编译器不一定能检查出来——编译器在这里的检查是一个抽查机制。但是array越界一定能检查出来——assert断言。

3.2array的缺点

1. 在栈上开空间,栈的空间只有8M。

2.vector可以完美替代array,vector也是可以检查越界的,并且在堆上开空间。

4.知识点补充

不可以直接从未实例化的类模板中直接取类型——因为编译器不会编译模板,所以不知道取出来的是类型还是静态成员

解决方案:前置typename——相当于向编译器保证取出来的是类型

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
template<class T>
class A {
public:
	typedef int asdf;
};
template<class T>
void test() {
//	A<T>::asdf a1 = 1; //报错
	typename A<int>::asdf a1 = 1;
	cout << a1;
}
int main() {
	test<int>();
	return 0;
}

二.模板的特化

2.1 概念

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板

// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{
 return left < right;
}
 
int main()
{
 cout << Less(1, 2) << endl; // 可以比较,结果正确
 
 Date d1(2022, 7, 7);
 Date d2(2022, 7, 8);
 cout << Less(d1, d2) << endl; // 可以比较,结果正确
 
 Date* p1 = &d1;
 Date* p2 = &d2;
 cout << Less(p1, p2) << endl; // 可以比较,结果错误
 
 return 0;
}

可以看到,Less绝对多数情况下都可以正常比较,但是在特殊场景下就得到错误的结果。上述示例中,p1指 向的d1显然小于p2指向的d2对象,但是Less内部并没有比较p1和p2指向的对象内容,而比较的是p1和p2指 针的地址,这就无法达到预期而错误。

此时,就需要对模板进行特化。即:在原模板类的基础上,针对特殊类型所进行特殊化的实现方式

模板特 化中分为函数模板特化类模板特化

2.2 函数模板特化

函数模板的特化步骤:

1. 必须要先有一个原模版

2. 关键字template后面接一对空的尖括号<>

3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型

4. 函数形参表: 必须要和原模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。

// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{
     return left < right;
}
 
// 对Less函数模板进行特化
template<>
bool Less<Date*>(Date* left, Date* right)
{
    return *left < *right;
}
 
int main()
{
     cout << Less(1, 2) << endl;
 
     Date d1(2022, 7, 7);
     Date d2(2022, 7, 8);
     cout << Less(d1, d2) << endl;
 
     Date* p1 = &d1;
     Date* p2 = &d2;
     cout << Less(p1, p2) << endl; // 调用特化之后的版本,而不走模板生成了
     return 0;
}

但是,不建议搞函数模板特化,因为重载不仅好写,而且可读性也强。

bool Less(Date* left, Date* right)
{
 return *left < *right;
}

向这样直接重载就很香了。

2.3 类模板特化

2.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<int, char>" <<endl;}
private:
     int _d1;
     char _d2;
};
 
void TestVector()
{
     Data<int, int> d1;
     Data<int, char> d2;
} 
2.3.2 偏特化
template<class T1, class T2> 
class Data
{
public:
     Data() {cout<<"Data<T1, T2>" <<endl;}
private:
     T1 _d1;
     T2 _d2;
};

概念

偏特化:任何针对模版参数进一步进行条件限制设计的特化版本。比如对于以上模板类:

部分特化:

将模板参数类表中的一部分参数特化

// 将第二个参数特化为int
template <class T1> 
class Data<T1, int>
{
public:
     Data() {cout<<"Data<T1, int>" <<endl;}
private:
     T1 _d1;
     int _d2;
}; 

参数更进一步的限制:

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

比如限定指针类型:

//两个参数偏特化为指针类型 
template <typename T1, typename T2> 
class Data <T1*, T2*> 
{ 
public:
     Data() {cout<<"Data<T1*, T2*>" <<endl;}
 
private:
    T1 _d1; 
    T2 _d2; 
};

如果传指针,就走这个特化版本

注意:T1,T2比传的类型少一个*

举例:传<int*, int**>

实际:T1(int)        T2(int*)

或者是限定引用:

template<class T1, class T2>
class Data<T1&, T2&> {
public:
    Data() { cout << "class Data<T1&, T2&>" << endl; }
private:
    T1 _d1;
    T2 _d2;
};

此时,传引用就走这个特化版本。

总结:

1. 指定类型限定

2. 说明指针,限定所有指针类型

3. 说明引用,限定所有引用

注意:这三个偏特化可以混编。

三 模板分离编译

3.1 什么是分离编译

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

3.2 模板的分离编译

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

// a.h
template<class T>
T Add(const T& left, const T& right);
 
// a.cpp
#include"a.h"
template<class T>
T Add(const T& left, const T& right)
{
     return left + right;
}
 
// main.cpp
#include"a.h"
int main()
{
     Add(1, 2);
     Add(1.0, 2.0);
 
     return 0;
}

3.3 解决方法

1. 将声明和定义放到一个文件 "xxx.hpp" 里面或者xxx.h其实也是可以的。推荐使用这种。

2. 模板定义的位置显式实例化。这种方法不实用,不推荐使用。

4. 模板总结

【优点】

1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生

2. 增强了代码的灵活性

【缺陷】

1. 模板会导致代码膨胀问题,也会导致编译时间变长——每实例化出一个模板类(函数),就会多个几十或上百行的代码。

2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误

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

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

相关文章

CSS线性渐变拼接,一个完整的渐变容器(div),要拆分成多个渐变容器(div),并且保持渐变效果一致

1 需求 一个有渐变背景的div&#xff0c;需要替换成多个渐变背景div拼接&#xff0c;渐变效果需要保持一致&#xff08;不通过一个大的div渐变&#xff0c;其他子的div绝对定位其上并且背景透明来解决&#xff09; 2 分析 主要工作&#xff1a; 计算完整div背景线性渐变时的…

福建聚鼎:装饰画店铺怎么做盈利快

在艺术的殿堂里&#xff0c;装饰画店铺是一扇通往美与创意的门。要想让这扇门快速盈利&#xff0c;我们需要从多个维度出发&#xff0c;打造一个独特且吸引人的艺术空间。 我们要注重产品的独特性。每一幅装饰画都应该是独一无二的艺术品&#xff0c;它们不仅仅是墙面的装饰&am…

Linux——IO模型_多路转接(epoll)

目录 0.往期文章 1.epoll的三个接口 1.epoll_create 2.epoll_ctl 结构体 epoll_event 3.epoll_wait 2. epoll的工作原理&#xff0c;和接口对应 1.理解数据到达主机 2.epoll的工作原理 3.基于epoll的TCP服务器&#xff08;代码) 辅助库 基于TCP的Socket封装 服务器代…

集运系统如何多维度展现企业业务情况?

在集运行业&#xff0c;数据是企业决策的重要依据。为了在竞争中保持优势&#xff0c;企业需要一套高效、灵活且可靠的管理工具来应对市场的快速变化。易境通集运系统以其全面而精细的统计报表功能&#xff0c;成为企业决策优化和业务增长的重要助手。 易境通集运系统https://…

OpenLayers3, 箭头线绘制实现

文章目录 一、前言二、代码实现三、总结 一、前言 本文基于OpenLayers3&#xff0c;实现绘制箭头线的功能。 二、代码实现 <!DOCTYPE html> <html> <head><title>绘制箭头线</title><link href"../../libs/ol3/ol.css" rel"…

山东省大数据职称考试(2)

注意&#xff1a;数据本身不具备价值。 线性表的顺序存储结构是指用一段地址连续的存储单元依次存储线性表的数据元素。 面向对象程序设计的特点包括&#xff1a;抽象、封装、继承、多态123。其中&#xff0c;抽象用于描述问题的高度概括、分类和抽象&#xff0c;封装实现了数据…

物料信息库管理杂谈

在国内某大型电子设备厂调研时&#xff0c;听到研发人员说&#xff0c;采购部门总是不能及时地采购所需要物料&#xff0c;导致进度延迟&#xff1b;而采购人员常常抱怨说&#xff0c;研发人员选用的物料很难采购&#xff1b;同时&#xff0c;生产人员也认为生产排期很难进行&a…

FGF23:家族靶向治疗先行者

成纤维细胞生长因子23&#xff08;FGF23&#xff09;属于FGF19亚家族成员&#xff0c;由成骨细胞、骨细胞和骨髓合成&#xff0c;是磷酸盐和钙稳态的重要调节剂&#xff0c;同时与铁稳态、炎症和红细胞生成也有关。 &#xff08;数据来源AlphaFold&#xff09; FGF23由251个氨…

内联函数与动态内存分配

内联函数 • 调用普通函数的问题&#xff1a; 每个普通函数调用语句都需要发生跳转操作&#xff0c;这种跳转操作会带来时间开销。 • 内 联就是用 函数已被编译好的二进制代码 &#xff0c; 替换 对该函数的调用指令 • 内 联在保证函数特性的同时&#xff0c;避免了函数 调用…

什么是Java以及Java的发展历程

Java是什么 搜索百度百科词条 Java是一门面向对象的编程语言&#xff0c;不仅吸收了C语言的各种优点&#xff0c;还摒弃了C里难以理解的多继承、指针等概念&#xff0c;因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表&#xff0c;极好地…

瞩“M”蓉城,驾趣“耍起” 全新BMW M5策马领衔,宝马集团13款新车闪耀成都车展

宝马秉持长期主义&#xff0c;以强大产品和创新体验&#xff0c;满足中国客户需求2024是BMW M大年&#xff0c;车型数量将扩至23款&#xff0c;几乎覆盖BMW所有细分市场全新BMW M5中国首秀&#xff0c;即将于今年年底上市 以“精简有道”融合性能美学与空气动力学&#xff0c;设…

实用好软-----电脑端 Kuvid工具 支持上千网站的视频下载软件

今天分享的这款软件支持很多网站视频下载 。全中文界面。操作比较简单。初步测试了下。下载B站视频操作方便 其他视频界面个别会解析错误。 软件主界面和相关设置界面 注意&#xff1a;设置中的自定义FFMPEG通常不需要开启,需要指定的路径是ffmpeg.exe的路径,不是所下载的安装…

2024高效获客转化指南 | 「人群模型」详解

营销进入“以人为本”的时代&#xff0c;小红书以其独特的UGC社区生态&#xff0c;在营销“人影响人”的传播链路中发挥着关键作用。 本期&#xff0c;千瓜就营销传播中“人”的研究展开探讨&#xff0c;通过解析人群模型、品牌案例&#xff0c;详细解读营销策略方法及应用&…

华为USG6625F设备ipsec隧道无IKE v1版本解决办法

新华为USG6625F防火墙&#xff0c;因需要和对端中心对接ipsec后发现无IKE V1版本&#xff0c;设备默认只有IKE v2版本&#xff0c;和对端对接隧道参数不一致&#xff0c;无法成功对接&#xff0c;因此需要下载相应的IKE v1插件后加载插件来解决该问题&#xff1b; USG6625F 版本…

Python自动化测试requests库深度详解

前言 发送HTTP请求 import requests# 登录的接口地址url http://............/login# 登录的参数params {"mobile_phone": 18300000000,"pwd": 12345678}# 请求头headers {X-Lemonban-Media-Type: lemonban.v2}# 发送登录请求# 请求类型为 Content-Typ…

《机器学习》 基于GANs构建数字图像生成器 探索深度学习世界

文章目录 引言生成对抗网络的基本原理生成对抗网络的数学表达生成对抗网络的应用生成对抗网络的挑战与优化生成对抗网络的实现示例结论&#xff1a;机器学习和ai技术的出现成为了C……SD……N 热榜的爹。 使用机器学习技术对热榜文章进行分析 引言 生成对抗网络&#xff08;Ge…

Training language models to follow instructionswith human feedback

Abstract 将语言模型做得更大并不会自动提高它们遵循用户意图的能力。例如&#xff0c;大型语言模型可能会生成不真实、有毒或对用户不有帮助的输出。换句话说&#xff0c;这些模型并未与用户对齐&#xff08;aligned&#xff09;。本文展示了一种通过人类反馈来对齐语言模型与…

Kubernetes 上安装 Jenkins

安装 Helm curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash添加 Jenkins Helm 仓库 首先添加 Jenkins Helm 仓库 helm repo add jenkins https://charts.jenkins.io helm repo update安装 Jenkins 使用 Helm 安装 Jenkins 的最新版本&…

2024最新gewe开发微信机器人教程说明

简介&#xff1a;本文将指导你如何搭建一个微信机器人&#xff0c;通过接入gewe实现智能回复与聊天功能。我们将从基础设置开始&#xff0c;逐步讲解如何配置机器人&#xff0c;并通过实例展示其实际应用。 随着人工智能技术的不断发展&#xff0c;智能机器人已经成为我们日常…

RS®SMM100A 矢量信号发生器重新定义中档仪器

R&S SMM100A 矢量信号发生器 100 MHz至44 GHz 产品综述 R&SSMM100A 矢量信号发生器在 100 MHz 至 44 GHz 的频率范围内提供一流的射频特性。这款仪器覆盖现有无线标准所使用的 6 GHz 以下的频段、新定义的最高 7.125 GHz 的 5G NR FR1 和 Wi-Fi 6E 频段以及最高 44 …