C++ 详谈模版(一)

C++中的new和模版 随着C++的学习,讲了C++的发展过程、流插入、流提取、函数缺省值、类与构造等等。接下来学习C++很方便的 玩意,函数模版。函数模版就像是模具一样,C++会自动用模版编译出合适的函数供程序员使用。以前不同类型相同操作的函数都能通过函数模版,只写一个来解决。这么说来,怪不得祖师爷会写出函数重载这样的优化。因为如此,函数模版大有作用。 阅读详情

目录

1. 泛型编程

2. 函数模板

函数模板概念

函数模板格式

函数模板的原理

函数模板的实例化

模板参数的匹配原则

3. 类模板

类模板的定义格式

类模板的实例化


1. 泛型编程

如何实现一个通用的交换函数呢?

void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}
void Swap(double& left, double& right)
{
	double temp = left;
	left = right;
	right = temp;
}
void Swap(char& left, char& right)
{
	char temp = left;
	left = right;
	right = temp;
}

使用函数重载虽然可以实现,但是有一下几个不好的地方:

1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增 加对应的函数

2. 代码的可维护性比较低,一个出错可能所有的重载均出错

那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?

如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同 材料的铸件(即生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只 需在此乘凉。

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

2. 函数模板

函数模板概念

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生 函数的特定类型版本。

函数模板格式

template<typename T1, typename T2,......,typename Tn>

返回值类型 函数名(参数列表){}

template<typename T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}

注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)

函数模板的原理

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器

  在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。  

函数模板的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。

隐式实例化:让编译器根据实参推演模板参数的实际类型

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.0, d2 = 20.0;
	Add(a1, a2);
	Add(d1, d2);
	/*
	该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
	通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有
	一个T,
	编译器无法确定此处到底该将T确定为int 或者 double类型而报错
	注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要
	背黑锅
	Add(a1, d1);
	*/
	// 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化
	Add(a, (int)d);
	return 0;
}

显式实例化:在函数名后的<>中指定模板参数的实际类型

int main(void)
{
	int a = 10;
	double b = 20.0;
	// 显式实例化
	Add<int>(a, b);
	return 0;
}

如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

模板参数的匹配原则

一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数

// 专门处理int的加法函数
int Add(int left, int right)
{
	return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
	return left + right;
}
void Test()
{
	Add(1, 2); // 与非模板函数匹配,编译器不需要特化
	Add<int>(1, 2); // 调用编译器特化的Add版本
}

对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板

// 专门处理int的加法函数
int Add(int left, int right)
{
	return left + right;
}
// 通用加法函数
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
	return left + right;
}
void Test()
{
	Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化
	Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
}

模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

3. 类模板

类模板的定义格式

template<class T1, class T2, ..., class Tn>
class 类模板名
{
	// 类内成员定义
};
#include<iostream>
using namespace std;
// 类模版
template<typename T>
class Stack
{
public:
	Stack(size_t capacity = 4)
	{
		_array = new T[capacity];
		_capacity = capacity;
		_size = 0;
	}
	void Push(const T& data);
private:
	T* _array;
	size_t _capacity;
	size_t _size;
};
// 模版不建议声明和定义分离到两个文件.h 和.cpp会出现链接错误,具体原因后面会讲
template<class T>
void Stack<T>::Push(const T& data)
{
	// 扩容
	_array[_size] = data;
	++_size;
}
int main()
{
	Stack<int> st1; // int
	Stack<double> st2; // double
	return 0;
}

类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

// Stack是类名,Stack<int>才是类型
Stack<int> st1; // int
Stack<double> st2; // double
C++11模版元编程 模版元编程(template metaprogram)是C++中最复杂也是威力最强大的编程范式,它是一种可以创建和操纵程序的程序。模版元编程完全不同于普通的运行期程序,它很独特,因为模版元程序的执行完全是在编译期,并且模版元程序操纵的数据不能是运行时变量,只能是编译期常量,不可修改,另外它用到的语法元素也是相当有限,不能使用运行期的一些语法,比如if-else,for等语句都不能用。 阅读详情

相关推荐

C++之模板编程

C++之模板编程,分析清晰合理,源自不错的学者,转载原文有注释

C++中模板讲解

模板1. 泛型函数2. 函数模板函数模板概念函数模板格式函数模板的原理函数模板的实例化模板参数的匹配原则3. 类模板类模板的定义格式类模板的实例化 1. 泛型函数 如何实现一个通用的交换函数呢? void Swap(int& left, int& right) { int temp = left; left = right; right = temp; } void Swap(double& left, double& right) { double temp = l

aaaaauaan的博客 463

一个Android应用层开发如何转型深入Android Framework?

不知何时起,单纯的Android应用层开发越来越少了,主流技术演变也越来越快,从之前的rxjava到如今的协程,从之前MVC到如今的MVVM,还有Flutter、Compose等技术,可以说是日新月异。

m0_64420071的博客 1910

C++模板完整版

本文主要对C++中的模板进行了完整的总结。

顾得泉的博客 1894

PCB过孔电流承载解析:完整指南与数据参考

深入解析PCB过孔的电流承载能力,结合实际应用场景提供可靠设计参考。涵盖影响载流的关键因素,并整理实用的pcb过孔与电流对照一览表,帮助工程师优化布局与布线。

weixin_35677363的博客 630

BlenderGis安装碰到问题,ImageIO、无法点击和地图不加载

BlenderGis安装碰到问题,ImageIO、无法点击和地图不加载问题

qq_45176349的博客 4964

c++模板编程

模板引入 模板主要是用来解决类库与类库使用不是一个人,编写类库时,不能确定使用类库的人会传入什么类型的数据,而做的一个类型抽象,编译器根据具体调用类库的时候,调用者传入的参数自动推导出数据类型,来替换类库中的数据类型。template关键字定义一个模板,typename关键字指定模板类型抽象名称。示例如下: template<typename T> void myswp(T &a,T &b) //交换数据 { T temp; temp=a; ...

习惯有你 3527

Qt快速读取Excel文件

网上很多读取方式都是如下形式,太慢了,打开文件+读取文件要6s以上,实在是受不了! QAxObject excel("Excel.Application"); excel.setProperty("Visible", false); QAxObject *work_books = excel.querySubObject("WorkBooks"); work_boo...

c+c++的博客 2万+

C++编程之模板编程

模板是 C++ 提供的泛型编程特性,可以编写与类型无关的代码,使得代码更加灵活和可复用。模板包括函数模板和类模板,以及高级特性如模板特化模板偏特化和模板元编程。// 函数模板// 实例化为 int 类型// 实例化为 double 类型// 实例化为 char 类型return 0;Chars: B// 类模板private:T value;public:// 实例化为 int 类型// 实例化为 double 类型return 0;Value: 123。

K 969

grafana 配置页面告警

Rate 下拉选择也可,保持默认也可。By label 选择一个比如选择filename。配置无数据或者错误数据的时候如何处理,这里选择 Normal (表示当做正常不会告警)单机 node_name 标签,选择一个主机,选好后单机 Show logs。单机 New floder,如果之前配置过,也可以选择。单机 Save contact point 保存即可。会跳出如下对话框(如果没有跳出就自己单机选择下)完成后会自动生成如下图,告警规则部分就配置好了。选择告警接收方式(这里选择企业微信 WeCon)

weixin_40548182的博客 3251

VLA算法总结对比——RT1 / RT2 / Pi0 / Octo/ RDT / OpenVLA

本文主要针最近比较经典的VLA算法进行对比总结,暂不涉及到代码细节和实验细节上的展开,仅仅是从大面上掌握下目前VLA的一些思路和方法。

weixin_44580210的博客 9489

【C++】详谈模版

深入了解C++的模版机制...

Dooo_yh的博客 2609

量化交易新手入门:从零开始搭建你的第一个Python交易策略(附完整代码)

本文为量化交易新手提供从零开始搭建Python双均线策略的完整指南,涵盖环境配置、数据获取、策略实现及风险管理等关键步骤。通过详细的代码示例和实践建议,帮助读者快速掌握量化交易的核心技术,并避免常见陷阱。文章特别强调Python在量化交易中的技术革新优势,适合希望进入金融科技领域的初学者。

weixin_26905487的博客 443

C++模版:从基础到进阶

在C++中,模版的定义必须和声明在同一个文件中,否则编译器将无法找到模版的定义。这是因为编译器需要看到模版的完整定义才能生成模版的实例。因此,我们通常将模版的定义放在头文件中。

码事漫谈 1476

把 sy-* 带进 ABAP CDS:ABAP 7.50 里的环境信息新姿势($session 与 @Environment.systemField 实战)

摘要:ABAP 7.50在CDS视图中引入两种获取环境信息的方式:1)直接使用$session会话变量读取用户、客户端和系统语言;2)通过@Environment.systemField注解参数,由Open SQL自动注入系统字段。$session方式简单但依赖Open SQL访问路径,非ABAP环境下可能失效;注解参数方案更工程化,依赖关系明确且支持测试。建议ABAP体系内优先使用$session,对外接口采用参数化方案。两种方式各有适用场景,正确选择可避免潜在风险。(148字)

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 151

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

【C++笔记】初始模版和STL简介

哈喽,各位小伙伴大家好!上期我们讲了C++的编译器优化和内存管理。今天我们来讲解C++模版和STL库。话不多说,我们直接进入正题!向大厂冲锋!STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。

大白的编程日记. 1638

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

C++ 模版进阶

不过在C++20之后就支持double和指针等内置类型作为非类型模版参数,但是依然不支持如string等非内置类型。并且传进来的这个N是常量,是不会被修改的。关于非类型模版参数的运用,很多场景还是用于定义一个新的数组。再看看c++标准库中非类型模版参数的运用:C++11中加入了一个array类(用类封装的静态数组),其中就使用到了非类型模版参数使用:那么array有什么优势呢?在C语言中,由int a[10]这样定义出的数组中,对于越界的检查是采取的:先设置标志位随机抽查。

2301_79501467的博客 1311

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

【C++深入系列】:模版详解(上)

想要学会c++的模版,看这篇文章就够了!

努力努力再努力wz的博客 2359

C++模版进阶

通常情况下,使用模版可以实现一些与类型无关的代码,但对于一些特殊类似的可能会得到一些错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模版。//特化--特殊处理bool Less} //特化--特殊处理 template < > bool Less < Date * >(Date * const & left , Date * const & right) {return 0;

m0_73523775的博客 1151

泛型的诗意——深入C++模板的艺术与科学(模版进阶)

模版参数分为类型模版形参和非类型形参;template<class T,size_t N = 10> //可以给一个缺省参数给予非模版形参private:T _arr[N];//这样的话可以定一个定长的数组int main()//可以构建一个数组长度为10的数组,也可以根据自己的兴趣来定//也可以根据自己的兴趣定一个长度的数组,虽然说很鸡肋,但在某一个方面还是很实用的。

effort123_的博客 7997

C++——模版

模版、C++

2303_78442132的博客 1810

探索C嘎嘎:模版初阶

其实函数模版就已经讲述了许多模版的特性了,所以在类模版的时候小编会少说一点知识点,不然就显的我水字数了template //不一定就这些class wang//类内成员函数的定义或者类内成员的定义public:_size = 0;int _size;

effort123_的博客 3058
上一篇: 数据结构进阶 详谈红黑树
下一篇: C++ 详谈模版(二)
万我.
博客等级 码龄1年 460粉丝 93原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值