【C++模版】模版进阶 {非类型模版参数; 模版的特化; 模版的分离编译; 模版总结}

news2024/11/17 0:56:17

一、非类型模版参数

  1. 模板参数分类型形参与非类型形参。
    • 类型形参:出现在模板参数列表中,跟在class或者typename之后的参数类型名称。
    • 非类型形参:就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用
  2. C++11新增了array容器,array实际上就是模板类型的静态数组:
//array的部分底层实现等效于以下代码:
template<class T, size_t N = 10> //不管是类型参数还是非类型参数都可以给默认值
class array
{
public:
	T& operator[](size_t index){
        assert(index < _size); //会对访问范围进行检查
        return _array[index];
    }
	const T& operator[](size_t index)const{
        assert(index < _size);
        return _array[index];
    }
	size_t size()const{return _size;}
	bool empty()const{return 0 == _size;}
private:
	T _array[N]; //静态数组
	size_t _size = N;
}

array VS 普通数组

  • array对比普通数组的优势在于:array对访问范围进行严格的检查,基本不会出现越界访问的问题。

  • 而普通数组只对范围后的部分空间进行抽查;且只检查越界写,不检查越界读;

#include <iostream>    
#include <array>    
using namespace std;    
      
int main()    
{    
    array<int, 10> a1;    
    //a1[10];  //严格检查,运行崩溃    
    //a1[15];  //严格检查,运行崩溃  
    
    int a2[10];
    cout << a2[10] << endl;   //越界读,正常运行 
    cout << a2[15] << endl;   //越界读,正常运行 
    //a2[10] = 1;  //越界写,部分抽查,运行崩溃  
    a2[20] = 1; //越界写,部分抽查,正常运行  
    cout << a2[20] << endl;                                                    
}

注意:

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

  2. 非类型模板参数必须传常量(const变量也行),不能传变量。

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


二、模版的特化

2.1 概念

模版的特化,即在原模板类的基础上针对特殊类型所进行特殊化的实现方式。

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

2.2 函数模版的特化

函数模板的特化步骤:

  1. 必须要先有一个基础的函数模板
  2. 关键字template后面接一对空的尖括号<>
  3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
  4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。
//1. 基础函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{
	return left < right;
}

// 对Less函数模板进行特化
template<> //2.
bool Less<Date*>(Date* left, Date* right) //3.4.
{
    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;
}

注意:一般情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都是将该函数直接给出。该种实现简单明了,代码的可读性高,容易书写。因为对于一些参数类型复杂的函数模板,特化时比较复杂,因此函数模板不建议特化。

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;
};
//两个参数偏特化为引用类型
template <typename T1, typename T2> //限制特化模版
class Data <T1&, T2&>
{
public:
	Data(const T1& d1, const T2& d2)
	: _d1(d1)
	, _d2(d2)
	{
		cout<<"Data<T1&, T2&>" <<endl;
	}
private:
	const T1 & _d1;
	const T2 & _d2;
};
void test2 ()
{
	Data<double , int> d1; // 调用特化的int版本——部分特化
	Data<int , double> d2; // 调用基础的模板
	Data<int *, int*> d3; // 调用特化的指针版本——限制特化
	Data<int&, int&> d4(1, 2); // 调用特化的引用版本——限制特化
}

三、模版的分离编译

3.1 什么是分离编译

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

3.2 模板的分离编译

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

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

// a.cpp
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;
}

像这样模版的分离编译会发生链接错误,原因如下:
在这里插入图片描述

错误原因:编译过程中,a.cpp中定义的函数模版未能完成实例化。由于类型不明确,其代码也就没有编译成指令,该函数也就没有进入符号表。链接时自然就找不到了。

3.3 解决方法

  1. 将模版的声明和定义放到一个.hpp 或者.h文件中其实也是可以的。推荐使用这种方法。

    • 头文件在预处理阶段展开,使模版的定义和调用在同一文件下。模版的实例化能够正常进行,且函数的地址在编译阶段就可以确定。

    • 模版的声明和定义在同一个文件中但可以分开来写:简单函数直接在类中定义,默认内联;复杂函数在类外定义,需要写明类域。声明和定义分离能使模版的结构更清晰,代码的可读性更高。

注意:当指定一个没有经过实例化的类模版其中的内嵌类型(内部类或typedef)时,需要在类型前加typename;告诉编译器,后面这一串是类型不是静态成员。

  1. 在模板定义的位置使用template + 类型显式实例化。这种方法不实用,不推荐使用。

    • 每调用一种新类型的模版,就需要在源文件中(模板定义的位置)手动进行一次显式的实例化,不实用。

四、模版总结

【优点】

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

【缺陷】

  1. 模板会导致代码膨胀问题,也会导致编译时间变长
  2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误

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

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

相关文章

mysql中的锁浅析

前言 MySQL 锁机制是保证多个并发事务同时访问数据库时数据一致性的重要手段&#xff0c;也是 MySQL 的重要特性之一。在实际开发使用 MySQL 数据库时&#xff0c;了解并掌握 MySQL 的锁机制非常重要&#xff0c;因为不正确的锁机制使用很容易出现严重的性能瓶颈和数据不一致等…

尚硅谷大数据hadoop教程_mapReduce

p67 课程介绍 p68概述 p69 mapreduce核心思想 p70 wordcount源码 序列化类型 mapReduce三类进程 p71 编程规范 用户编写的程序分成三个部分&#xff1a;Mapper、Reducer和Driver。 P72 wordcount需求案例分析 p 73 -78 案例环境准备 &#xff08;1&#xff09;创建maven…

写代码?文心一言or文言文,谁更胜一筹?新工具或许可堪重任

中国版的ChatGPT“文心一言”写代码能力尚浅 被称为中国版的“ChatGPT”的“文心一言”可以说是上市几个月了&#xff0c;很多用户都受到了邀请码来体验&#xff0c;遗憾的是&#xff0c;小编早就申请了&#xff0c;但还在排队等待中。虽然没有亲自体验过百度的“文心一言”&a…

NET HELPMSG 3534 报错(以及其他一些在配置过程中遇到的问题)

使用了带管理员权限的 PowerShell&#xff08;即在管理员权限下运行CMD&#xff09; 然后进行安装和服务启动操作 1、清空 MySQL 下的 data 文件夹&#xff1b; 2、确保系统环境变量中已经配置了 mysql 的 bin 目录到Path中&#xff1b; 3、执行以下命令&#xff1a; sc delet…

基于条件风险价值CVaR的微网动态定价与调度策略(matlab代码)

目录 1 主要内容 模型示意图 电能交易流程 模型亮点 2 部分代码 3 程序结果 4 下载链接 1 主要内容 程序复现文章《A cooperative Stackelberg game based energy management considering price discrimination and risk assessment》&#xff0c;建立基于主从博弈的考…

【封装frame模型 Objective-C语言】

一、计算每行的高度 1.计算每行的高度,它就等于最后这个控件, 如果说,当前这行是有配图的,那么这个行高,就等于这个配图最大的Y值,加上一个margin, 如果说,这行是没有配图的 如果说,这行是没有配图的 那么就等于它正文的最大的Y值,加一个margin, 是不是很简单,…

海昌海洋公园携手盖雅工场,数字化人才管理助力企业踏浪前行

五一假期刚刚结束&#xff0c;但各地主题公园里的游客依然爆满。在这种客流高峰期&#xff0c;游客更加关注乐园的细节和服务水平&#xff0c;保障服务品质和顾客体验是各地主题乐园在竞争中脱颖而出的关键因素之一。为此&#xff0c;乐园高峰期需要大量招聘短期工、临时工、兼…

全网最详细,全链路压力测试整理,银行系统项目...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 软件测试银行业务…

k8s污点与容忍

1.前言 污点是给node节点打上污点标签&#xff0c;使得pod不能往该node节点上调度&#xff0c;污点有三种模式&#xff0c;分别是NoSchedule、PreferNoSchedule、NoExecute&#xff0c;容忍是给pod打上和node节点一样的污点标签&#xff0c;使pod能调度到带有该污点标签的node…

为什么使用 Javascript 流程图进行过程可视化

DhtmlxDiagram 是一个随时可用的库&#xff0c;只需几行代码就能生成任何你需要的图表。借助自动布局和实时图编辑器&#xff0c;以整齐的层次结构可视化复杂数据。JavaScript dhtmlxDiagram可以向Web应用程序中添加漂亮的交互式图表&#xff0c;图表和图形。借助这种轻巧而快速…

第六篇、基于Arduino uno,控制180度舵机(SG90)转动——结果导向

0、结果 说明&#xff1a;让舵机转动&#xff0c;需要用PWM来控制&#xff0c;下面的程序是舵机从0度一直转到180度&#xff0c;然后又从180度转到0度的这样一个过程。 1、外观 说明&#xff1a;虽然舵机的型号有很多种&#xff0c;但是只要是180度的舵机&#xff0c;控制方…

XVS-460-15MPI-1-10伊顿触摸屏

​ XVS-460-15MPI-1-10伊顿触摸屏 触摸屏感应到我们手指的触摸是因为当手指触摸屏幕上的一个具体位置时&#xff0c;相当于为屏幕发送了一个精确的电子信号。触摸屏有很多类型&#xff0c;大致分为电阻式触摸屏和电容式触摸屏。目前应用最广泛的是“电容式触摸屏”。 我们手机…

华为OD机试之考勤信息(Java源码)

考勤信息 题目描述 公司用一个字符串来表示员工的出勤信息 absent&#xff1a;缺勤late&#xff1a;迟到leaveearly&#xff1a;早退present&#xff1a;正常上班 现需根据员工出勤信息&#xff0c;判断本次是否能获得出勤奖&#xff0c;能获得出勤奖的条件如下&#xff1a; 缺…

Python编程环境搭建:Windows中如何安装Python

在 Windows 上安装 Python 和安装普通软件一样简单&#xff0c;下载安装包以后猛击“下一步”即可。 Python 安装包下载地址&#xff1a;https://www.python.org/downloads/ 打开该链接&#xff0c;可以看到有两个版本的 Python&#xff0c;分别是 Python 3.x 和 Python 2.x&…

Nginx网站服务详解(编译安装及系统服务添加)

目录 一、Nginx的相关知识 1&#xff09;Nginx的简介 Nginx&#xff1a; Apache&#xff1a; 2&#xff09;Apache与Nginx的区别 Nginx对比Apache的优势&#xff1a; apache相对于nginx的优点 &#xff1a; 3&#xff09;Nginx的进程 Nginx有两个进程&#xff1a;…

Java的volatile

介绍 volatile volatile 关键字可以说是 Java 虚拟机提供的最轻量级的同步机制&#xff0c;但是它并不容易被正确、完整地理解&#xff0c;以至于许多程序员都习惯去避免使用它&#xff0c;遇到需要处理多线程数据竞争问题的时候一律使用 synchronized 来进行同步。了解 volat…

Flutter:功能型组件(2)- 弹出菜单、弹出提示

弹出菜单 PopupMenuButton 使用PopupMenuButton&#xff0c;点击时弹出菜单 Center(child: PopupMenuButton<String>(initialValue: Math, // 初始值itemBuilder: (context) {// 子项构造函数return <PopupMenuEntry<String>>[const PopupMenuItem(value:…

svg教程-初始svg

第一章 认识svg 简单来说&#xff1a; 位图&#xff1a;放大会失真图像边缘有锯齿&#xff1b;是由像素点组成&#xff1b;前端的 Canvas 就是位图效果。矢量图&#xff1a;放大不会失真&#xff1b;使用 XML 描述图形。 我在 知乎 上找了一个图对说明一下。 左边是位图&am…

华为开发者大会2023官宣,华为云在憋什么大招?

文丨智能相对论 作者丨沈浪 华为云也坐不住了。 在此之前&#xff0c;百度、阿里、商汤、科大讯飞等国内科技厂商以及微软、谷歌等国际巨头都已经发布了自家的大模型新品以及AIGC等相关应用。而华为云手握盘古大模型&#xff0c;却始终按兵不动&#xff0c;迟迟没有正式进场…

实验篇(7.2) 02. 部署物理实验环境(上)❀ 远程访问

【简介】当大家了解到并不需要很高的代价就可以动手做FortiOS 7.2的实验&#xff0c;很多人愿意尝试使用FortiGate防火墙硬件来学习最验难掌握的远程访问部分&#xff0c;这里我们将学习现场部署一套物理实验环境&#xff0c;让大家看到&#xff0c;在一张桌子上&#xff0c;在…