Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何编写一个通用的函数?

如何编写一个通用的函数?

作者头像
初阶牛
发布于 2023-10-14 10:00:22
发布于 2023-10-14 10:00:22
25300
代码可运行
举报
文章被收录于专栏:C语言基础C语言基础
运行总次数:0
代码可运行

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏1: 🍔🍟🌯C语言初阶 🐻推荐专栏2: 🍔🍟🌯C语言进阶 🔑个人信条: 🌵知行合一 金句分享: ✨你要狠下心来去努力,努力变成一个很厉害的人.✨

前言

本文主要讲解如何使用简单的模板,了解模板的原理以及基本知识.

一、函数模板

模板的作用:

C++模板的作用是支持泛型编程。==泛型编程=是一种编程范式,它只考虑算法或数据结构的抽象,而不考虑具体的数据类型。通过使用模板,可以编写一种通用的算法或数据结构,而不需要为每种数据类型都编写一遍相关代码。模板可以用于函数、类、结构体等地方,以实现通用的算法和数据结构。使用模板可以提高代码的复用性和可读性,减少代码的重复编写。

示例:实现一个交换函数.

使用模板之前:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void swap(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}
void swap(double& a, double& b)
{
	double tmp = a;
	a = b;
	b = tmp;
}

void swap(char& a, char& b)
{
	char tmp = a;
	a = b;
	b = tmp;
}

void test1()
{
	//交换整形
	int a = 2, b = 3;
	cout << "a=" << a << "  " << "b=" << b << endl;
	swap(a, b);
	cout << "a=" << a << "  " << "b=" << b << endl;

	//交换字符型
	char c1 = 'd', c2 = 'f';
	cout << "c1=" << c1 << "  " << "c2=" << c2 << endl;
	swap(c1, c2);
	cout << "c1=" << c1 << "  " << "c2=" << c2 << endl;
	//交换...
}

上述实现过程中使用函数重载实现.但是函数重载会有一些不合适的问题.

  1. 函数重载只是重载的函数类型不同,代码复用率比较低,对于一个新的类型又要增加新的函数.
  2. 由于功能基本一样,只是类型不同,导致代码的可维护性比较低,一个出错可能所有的重载均出错,均要修改.

这时,函数模板就派上用场了.

(1)函数模板的格式

template<typename T1, typename T2,......,typename Tn> 返回值类型 + 函数名 +(参数列表){} 其中,typename 可以使用class代替,不能使用struct代替.

示例:使用模板后的通用交换函数.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template <class T>//模板
void swap(T& a, T& b)//T会根据传参的对象进行推导为相应的类型
{
	T tmp = a;
	a = b;
	b = tmp;
}
void test1()
{
	//交换整形
	int a = 2, b = 3;
	cout << "a=" << a << "  " << "b=" << b << endl;
	swap(a, b);
	cout << "a=" << a << "  " << "b=" << b << endl;

	//交换字符型
	char c1 = 'd', c2 = 'f';
	cout << "c1=" << c1 << "  " << "c2=" << c2 << endl;
	swap(c1, c2);
	cout << "c1=" << c1 << "  " << "c2=" << c2 << endl;
	//交换...
}

(2)函数模板的原理(重点)

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

这就类似于古代的印刷术,如果每本书都需要手写,那效率是否太低了,还有各种情况可能会出错.但是印刷术的使用,就可以使用模具生成.

函数模板的原理是通过将类型参数化,使函数能够在编译时根据实际参数的类型推断生成具体的函数实例。编译器会根据调用函数时的参数类型,实例化出适合该类型的函数版本。

比如: 当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码.当用int类型使用函数模板时,编译器通过对实参类型的推演,将T确定为int类型,然后产生一份专门处理int类型的代码.如上图所示.

(3)模板参数的显示实例化

上面我们实现的交换函数,模板根据传参时不同的参数,自动推演出函数参数的实际类型.我们称这类通过编译器进行自动推导的实例化模板参数称为模板参数的隐式实例化.

那什么是显示实例化呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template <typename T>
T add(const T& a, const T& b)
{
	return a + b;
}
void test1()
{
	int a = 2, b = 3;
	double d1 = 2.5, d2 = 4.1;
	cout << add(a, b) << endl;
	cout << add(d1, d2) << endl;
	//下面这句会报错,因为一个模板参数无法在一个函数中实例化为2个不同类型的参数,一个int,一个double
	//cout << add(a, d2) << endl;
}

一个函数模板参数在同一个函数中,无法被识别为不同的两个实例类型参数,当编译器推导出aint时,又推出d2double类型,则编译器陷入两难.

就好比: int:妈妈说今天不许出去玩! double:爸爸说今天可以出去玩! 编译器:我听谁的.

解决方案:

直接将参数先强转为一样的,当模板函数接收到参数时,就只有一样的结果了.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	//解决方法1:传参时将其中不同的参数强转,使参数们相同
	cout << add(a, (int)d2) << endl;
	cout << add((double)a, d2) << endl;

模板参数的显示实例化:

让爸妈先商量好听谁的.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	//解决方法2:显示指定模板的参数
	cout << add<int>(a, d2) << endl;	//听妈妈的
	cout << add<double>(a, d2) << endl;	//听爸爸的

我们应当是考虑如何在调用时采取不同的调用方式去满足我们的需求,千万不要想着去修改模板函数的返回值,参数使他们固定生成,那模板就不通用了,而且不是什么时候我们都可以去修改模板的. 错误示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template <typename T>
T add(const T& a, const int& b)//直接修改参数,进行固定
{
	return a + b;
}

(4)模板匹配

对于函数名相同的非模板函数和模板函数同时存在时,编译器会优先选择非模板函数.除非模板可以产生更好的匹配函数,才会选择模板.

编译器:有现成的为啥不用.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void swap(double& a, double& b)
{
	double tmp = a;
	a = b;
	b = tmp;
}
//template <class  T>
template <typename  T>//函数模板
void swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}
void test1()
{
	//交换double
	double d1 = 2.5, d2 = 4.5;
	//非模板函数和模板函数同时存在时,编译器优先选择非模板函数,有现成的为啥不用?非得自己去再模具刻一个?
	swap(d1, d2);
	cout << "d1=" << d1 << "  " << "d2=" << d2 << endl;
	
	//交换整形
	int a = 2, b = 3;
	//没有现成的非模板函数,则编译器调用模板函数去实例化一份
	swap(a, b);
	cout << "a=" << a << "  " << "b=" << b << endl;
}

交换double型数据时,会调用void swap(double& a, double& b)函数,因为有现成的可以调用. 交换int整形时,则会调用模板函数void swap(T& a, T& b),实例化生成int型的函数.

小知识: 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换. 因为模板函数的参数是通过参数类型进行推导的.

二、类模板

类模板的格式

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template <typename T>
class A
{
	//成员
}

类模板在后续学习STL时候会具体介绍,目前了解一下即可,使用方法与函数模板类似,这里就不过多介绍了.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template <typename T>
class A
{
public:
	A(size_t capacity = 10)
		: _data(new T[capacity])
		, _size(0)
		, _capacity(capacity)
	{}

	void push_back() {
		//...
	}
	~A()
	{
		delete _data;
		_size = 0;
		_capacity = 0;
	}

private:
	T* _data;
	size_t _size;
	size_t _capacity;
};


void test3()
{
	A<int> a1;			//实例化为存储int数据的类
	A<double> a2;		//实例化为存储double数据的类
}

本文只是对模板的初步了解,后续会遇到更加复杂的模板,比如多参数的模板等,知识一点点的学,不求速成,坚持一点点的积累,一起加油吧! 今天就讲到这里了,拜拜.

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-10-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【C++】初识模板
假设我们想实现一个交换函数,并且支持不同类型的参数实现,我们可以用 typedef 将类型进行重命名,例如以下代码:
YoungMLet
2024/03/01
1090
【C++】初识模板
【C++修炼之路】7. 模板初阶
如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件(即生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只需在此乘凉。
每天都要进步呀
2023/03/28
3680
【C++修炼之路】7. 模板初阶
C++从入门到精通——模板
C++模板是C++语言中的一种泛型编程技术,可以实现在编译期间生成不同类型的函数或类。通过使用模板,可以编写通用的代码,使其能够处理多种不同类型的数据。
鲜于言悠
2024/04/24
1310
C++从入门到精通——模板
【C++干货基地】探索C++模板的魅力:如何构建高性能、灵活且通用的代码库(文末送书)
那么我们是否可以让编译器像活字印刷一样,需要那种类型的函数直接生成一个就好了?
鸽芷咕
2024/05/26
1570
【C++干货基地】探索C++模板的魅力:如何构建高性能、灵活且通用的代码库(文末送书)
【C++】模板初阶
以实现交换函数为例,在C语言中即使是近乎完全一致的的功能,通过代码实现,只要参数不同,我们就需要写对应类型的不同函数名的函数,在之前的学习中,我们已经学习了函数重载,我们不再需要起不同的函数名,比起C语言方便不少,但是不容忽视的是函数重载仍然有不好的地方。
ZLRRLZ
2024/12/13
880
【C++】模板初阶
【C++篇】走进C++初阶模版:感受模版奇妙
相信我们都经历过如何写过很多种交换函数,冗余且代码量效率低,C++为了解决这一问题,变将模版引入C++语言。下面将详细讲解模版(Template)。
熬夜学编程的小王
2024/11/20
1070
【C++篇】走进C++初阶模版:感受模版奇妙
C++-模板基础
大家在学习过程中一定写过swap函数吧,那么swap函数的可以写成很多种形式,因为形参的类型可以是任意类型,那么我们如果想用多种swap函数的话,就意味着我们必须写多个swap函数吗?不是的,C++为了解决这个问题,引入了模板这个概念。
用户10923087
2024/02/05
1150
C++-模板基础
【C++】C++模板基础知识篇
所以c++就提供了模板,就相当于一个模具,让编译器根据不同的类型利用该模子来生成代码。
zxctscl
2024/03/09
1200
【C++】C++模板基础知识篇
初识模板及其STL
如果在C++中,存在一个摸具,通过给这个摸具中填充不同材料(类型),赖获得不同材料的锻件(即生成具体类型的代码),那么就会节省许多头发。对此C++提出模板的概念,对于模板分为函数模板以及类模板。
是店小二呀
2024/08/13
1140
初识模板及其STL
【C++学习】模板初阶&&STL简介
使用函数重载虽然可以实现,但是有一下几个不好的地方: 💞 1、重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数。 💞 2、代码的可维护性比较低,一个出错可能所有的重载均出错。
IsLand1314
2024/10/15
1160
【C++学习】模板初阶&&STL简介
【C++初阶】C++模板编程入门:探索泛型编程的奥秘
前言:在C++编程世界中,模板是一个强大的工具,它使得程序员能够编写更加通用、灵活和可重用的代码。通过模板,我们可以编写与类型无关的代码,这些代码可以在编译时根据所需的具体类型进行实例化。本文将带你走进C++模板的初阶世界,探索泛型编程的基石
Eternity._
2024/06/14
1690
【C++初阶】C++模板编程入门:探索泛型编程的奥秘
【C++】初识模板,拿来吧你
文章目录 一、泛型编程 二、函数模板 1.函数模板概念 2.函数模板格式 3.函数模板的原理 4 函数模板的实例化 1. 隐式实例化 2. 显式实例化 5.模板参数的匹配原则 三、类模板 1 类模板的定义格式 2 类模板的实例化 四、模板不支持分离编译(了解) 一、泛型编程 如何实现一个通用的交换函数呢? 我们可以针对不同的数据类型写出不同的交换函数 void Swap(int& left, int& right) { int temp = left; left = right;
平凡的人1
2022/11/15
2810
【C++】初识模板,拿来吧你
【C++】你想要的——印刷模板儿
 就拿交换函数来说,当我们交换不同类型的变量的值,那就需要不停的写交换函数的重载,这样代码复用率就较低,那我们能不能创造一个模板呢??
The sky
2023/04/12
4240
【C++】你想要的——印刷模板儿
C++模板初阶
在一个项目中,我们可能需要交换不同类型的数据。虽然C++支持函数重载,解决了C语言中函数名不能相同的问题,但是代码复用率任然极低
始终学不会
2023/03/28
6420
C++模板初阶
【C++】第七节—模版初阶+STL简介
那能否 告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?
云边有个稻草人
2025/04/03
590
【C++】第七节—模版初阶+STL简介
【C++】初识模板
在谈及本章之前,我们先来聊一聊别的。橡皮泥大家小时候应该都玩过吧,通常我们买来的橡皮泥里面都会带有一些小动物的图案的模子。我们把橡皮泥往上面按压,就会得到一个个具有该图案形状的橡皮泥。橡皮泥的颜色不同,得到的形状的颜色也不相同。就好像下面这样:
诺诺的包包
2023/03/24
5600
【C++】初识模板
【C++初阶】函数模板与类模板
于是,大佬心里就在想,能不能像铸铁一样,刻出一个模子(模板),然后通过浇筑不同的材料(不同的类型),从而锻造成不同材料制成的宝刀(不同类型的目标代码)
MicroFrank
2023/01/16
7990
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
通过阅读本文,你将能够掌握C++模板编程的基础知识,理解其背后的工作原理,并学会如何在实际项目中应用这些技术。
半截诗
2024/10/09
2580
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
C++之模板(上)
本文介绍了C++模板的基础概念,简单介绍了泛型编程,模板,以及模板中的函数模板与类模板等相关概念。
摘星
2023/04/28
4250
C++之模板(上)
【C++】模板初阶&&STL简介
1. 假设要交换两个变量的值,如果只是用普通函数来做这个工作的话,那么只要变量的类型发生变化,我们就需要重新写一份普通函数,如果是C语言,函数名还不可以相同,但是这样很显然非常的麻烦,代码复用率非常的低。 那么能否告诉编译器一个模板,让编译器通过模板来根据不同的类型产生对应的代码呢?答案是可以的。
举杯邀明月
2023/04/12
5250
【C++】模板初阶&&STL简介
相关推荐
【C++】初识模板
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验