C++之函数模板

C++中的函数模板 之前我们知道的交换两个变量的方法有宏定义、函数,这两种方式都能实现两个变量的交换,但是各有各的优缺点 宏定义: - 优点:代码复用,适合所有的类型 - 缺点:缺少类型检查,宏在预处理阶段就被替换掉,编译器并不知道宏的存在 函数: - 优点:真正的函数调用,编译器对类型进行检查 - 缺点:类型不同需要重复定义函数,代码无法复用 上边两种方式... 阅读详情

之前我们知道的交换两个变量的方法有宏定义、函数,这两种方式都能实现两个变量的交换,但是各有各的优缺点
    宏定义:
    - 优点:代码复用,适合所有的类型
    - 缺点:缺少类型检查,宏在预处理阶段就被替换掉,编译器并不知道宏的存在

    函数:
    - 优点:真正的函数调用,编译器对类型进行检查
    - 缺点:类型不同需要重复定义函数,代码无法复用

上边两种方式都各有利弊,但是在C++中,存在泛型编程的概念:即不考虑具体数据类型的编程方式(如下)

C++中的泛型编程有函数模板与类模板,这章我们先来了解函数模板
    函数模板是一种特殊的函数,可以使用不同的类型进行调用,对于功能相同的函数,不需要重复编写代码,并且函数模板与普通函数看起来很类似,区别就是类型可以被参数化

    函数模板通过template与typename两个关键字来定义,class也可以声明泛指类型,如下


以上内容来自:https://blog.youkuaiyun.com/lms1008611/article/details/81985815

下面是一些函数模板的实现:

#include<iostream>
using namespace std;

template <typename T>//声明即将定义一个模板了
void my_swap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}

int main()
{
	double i=1.025, j=1.075;
	int m = 1, n = 2;
	//编译器会推断T的数据类型
	my_swap(i, j);
	//显式指定类型,指定T的类型
	my_swap<double>(i, j);
	cout << "i=" << i << endl;
	cout << "j=" << j << endl;
	
	//第二次套用模板
	my_swap(m, n);
	//显式指定类型,指定T的类型
	my_swap<int>(m, n);
	cout << "m=" << m << endl;
	cout << "n=" << n << endl;

	return 0;
	system("pause");
}

注意事项:1.你要能让编译器判断出来你T的类型,不能出现二义性,例如:

my_swap(i, n);

2.不能出现模糊定义的概念,模板必须要确定出T的数据类型,即使你在整个模板函数中没有用到T,你又不显式的指定T的数据类型,那就废了,编译器也不会自动搞明白你的T的类型,程序就会报错。

Tips:使用模板时必须确定出通用数据类型T,并且能够推导出一致的类型。

给出一个算例:

案例描述:

* 利用函数模板封装一个排序的函数,可以对**不同数据类型数组**进行排序

* 排序规则从小到大,排序算法为**选择排序**

* 分别利用**char数组**和**int数组**进行测试

#include<iostream>
using namespace std;

template <typename T>//声明即将定义一个模板了
void my_swap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}

template<typename T>
void my_sort(T arry[],const int& length) {//形参数组名,共同拥有一段数组内存空间
	//选择排序法
	for (int i = 0; i < length; i++)
	{
		int min=i;
		for (int j = i + 1; j < length; j++)
		{
			if (arry[min] > arry[j])
				min = j;
		}
		if (min != i)
			my_swap(arry[min], arry[i]);
	}
}

template<typename T>
void my_print(T arry[],const int& length)
{
	for (int i = 0; i < length; i++)
	{
		cout << arry[i] << "\t";
	}
	cout << endl;
}

int main()
{
	char Arry[] = "asdfghjkl";
	int length = sizeof(Arry) / sizeof(char);//不能在模板里边去计算,容易出问题。
	//原因在于sizeof不是函数,而是一个运算符,由编译器来计算的,而不是运行的时候计算的,Arry接收的时候
	//用指针接收,并不知道这个数组的长度,因此会出错
	//所以说,在传数组的时候,往往还是要传入一个数组元素的个数这个参数
	my_sort(Arry,length);//传实参数组的首地址
	my_print(Arry,length);

	int A[] = {5,1,2,3,5,7,8,9,4,6};
	int length1 = sizeof(A) / sizeof(int);
	my_sort(A, length1);//传实参数组的首地址
	my_print(A, length1);

	return 0;
	system("pause");

普通模板与函数模板的区别

#include<iostream>
using namespace std;

template<typename T>
T my_swap(T a, T b)
{
	return(a + b);
}

int main()
{
	char a = 'a'; 
	int b = 2;
	int result = my_swap<int>(a, b);//隐式类型转换,前提是我显式的指定了T的类型(形参不要用引用)
	//如果不指定int,就不可以进行隐式类型转化。如何进行类型转化就是普通函数和函数模板的区别
	//普通函数自动就可以进行类型转换
	return 0;
	system("pause");
}

函数模板和普通函数的调用规则

1. 如果函数模板和普通函数都可以实现,优先调用普通函数

2. 可以通过空模板参数列表来强制调用函数模板

3. 函数模板也可以发生重载

4. 如果函数模板可以产生更好的匹配,优先调用函数模板

#include<iostream>
using namespace std;

void fun(int a, int b)
{
	cout << "普通函数" << endl;
}

template <typename T>
void fun(T a, T b)
{
	cout << "模板函数" << endl;
}

int main()
{
	int a = 0, b = 5;
	fun(a, b);//调普通函数或者模板函数其实都一样,这种情况下,优先调用普通函数
	fun<>(a, b);//当使用空模板的时候,此时会优先调用模板函数
	fun<int>(a, b);//同上,也调用模板函数
	
	char m = 'a';
	char n = 'b';
	fun(m, n);//编译器偷懒,认为我调用模板函数不存在类型转换,所以优先调用模板函数
	fun(a, m);//编译器优先普通函数,因为是自动类型推导,编译器认为不可发生隐式类型转换

	return 0;
	system("pause");
}

既然提供了函数模板,最好就不要提供重名的普通函数,否则容易出现二义性。

 模板函数在自定义数据类型下的处理办法

这也是模板函数的缺点,对于识别出来T是内置的数据类型,直接进行关系运算符进行运算,如果识别出来的T不是内置的数据类型,而是我自定义的比如Person数据类型,那么进行关系运算符进行运算的时候,就会出问题,那个时候就还要进行运算符重载或者再提供一个Person的重载版本,当识别出来T是Person时候,走下面的专属于Person类的代码,具体格式见下面最后一段代码:

#include<iostream>
#include<string>
using namespace std;

class Person {
public:
	Person(const string& s1, const int& age1):name(s1),age(age){}
	bool operator==(Person & p2); 
	string name;
	int age;

};
bool Person::operator==(Person & p2)
{
	if (this->age == p2.age)
		return true;
	else
		return false;
}

template <typename T>
bool compare(T& m1, T& m2)
{
	if (m1 == m2) 
		return true;
	else
		return false;
}
int main()
{
	int a = 0, b = 0;
	cout << boolalpha <<compare(a, b) << endl;//内置的数据类型进行等号判断,OK,可以
	Person p1("张三", 20), p2("李四", 20);
	cout << boolalpha << compare(p1, p2) << endl;//自定义的数据类型就不可以 了,因为在16行判断不出来p1和p2是否相等
	//解决办法1.是运算符重载2.是模板重载
	
	return 0;
	system("pause");
}

上面是利用运算符重载,下面是模板重载的方法

#include<iostream>
#include<string>
using namespace std;

class Person {
public:
	Person(const string& s1, const int& age1):name(s1),age(age){}
	string name;
	int age;

};

template <typename T>
bool compare(T& m1, T& m2)
{
	if (m1 == m2) 
		return true;
	else
		return false;
}
template<> bool compare(Person& m1, Person& m2)
{
	if (m1.age==m2.age)
	{
		return true;
	}
	else
	{
		return false;
	}
}

int main()
{
	int a = 0, b = 0;
	cout << boolalpha <<compare(a, b) << endl;//内置的数据类型进行等号判断,OK,可以
	Person p1("张三", 20), p2("李四", 20);
	cout << boolalpha << compare(p1, p2) << endl;//自定义的数据类型就不可以 了,因为在16行判断不出来p1和p2是否相等
	//解决办法1.是运算符重载2.是模板重载
	
	return 0;
	system("pause");
}
函数模板与宏定义 函数模板与宏定义。代码复用的不同方式的定义,包含了用函数模板实现代码复用,用宏定义展开为函数的定义与使用。 立即下载

相关推荐

UVM概述及uvm_component和uvm_object(一)

UVM:Universal Verification Methodology(通用验证方法学) UVM:是建立在systemverilog平台上的一个库,提供了一系列的接口,让我们能够更方便的进行验证。验证平台组成: Driver:用来把不同的激励施加给DUT; Monitor:用来检测DUT的输出; Scoreboard:专门用来比较期望值与monitor检测到的DUT输出; Refer

南国之邱 1万+

函数模板template <typename T>

本文实现了一个通用的快速排序函数模板,可以对任意数据类型进行排序。通过模板函数kuaipai()实现了快速排序算法,其中jizhu()函数用于确定基准值位置,change()完成元素交换。程序测试了四种数据类型的排序:整型数组、浮点型数组、字符数组和字符串数组,均能正确输出排序结果。该实现展示了模板编程在多数据类型处理中的优势,通过类型参数T实现了算法复用,避免了为每种数据类型重写排序代码的冗余。

2301_77212325的博客 186

CANoe VLAN配置的艺术:如何通过脚本自动化实现高效车载网络测试

本文深入探讨了CANoe VLAN配置的自动化实现,通过CAPL脚本与Python工具链的结合,提升车载网络测试效率。重点解析了硬件侧VLAN配置与软件侧VLAN配置的交互机制,并提供了实用的脚本开发示例和调试技巧,帮助工程师快速构建高效的自动化测试方案。

qqq44的博客 617

c++ 宏和模板

对单一模板提供的一个特殊实例,它将一个或多个模板参数绑定到特定的类型或值上。

南风知我意 1163

MAX30102心率血氧传感器

估算AC、DC值的方法如下:找两个波谷点,两个波谷点之间有一个波峰点,两个波谷点相连成一条直线,与Y轴平行的线穿过波峰点会与两个波谷点连接成的直线相交于一点,这个点就是DC点,DC点的Y轴对应值就是直流分量,AC分量的值为波峰点到DC点之间的差值。在医院测量中常用的一种血氧采集方式,如下图所示,光电传感器和光源分别置于手指的两侧,光源穿过手指被另一侧的光电二极管接收,根据光衰减量计算血氧浓度。那么,根据上面的Beer-Lambert 定理,针对测量的具体场景,测量过程的衰减为三层穿透物质衰减量的叠加。

qq_41861711的博客 1万+

EtherCAT从站协议栈---- sampleappl.c 文件解析

这个源文件实际上包含该项目的入口函数main函数。 那么如何找到入口函数呢? 可以进入debug的simulator模式,选中run to main(), 当执行完启动文件startup_cm3.s后就进入了main函数(注意在main函数之前还进入了SystemInit函数), 如下图所示: 这个main函数主要架构如下: int main(void) { HW_Init(); /*PDI(过程数据接口)初始化,这里用的是MCI接.

Jiawei_Z的博客 3069

c++ 常见宏、模板用法【1】

记录几个常见的好用的宏和模板编程技巧的示例,它们可以提高代码的可读性、可维护性和灵活性,为开发人员提供了更多的选择和工具来处理复杂的编程问题。

hanhan的博客 1076

【低空经济】森林火情高精度监测与早期预警无人机巡护方案

在全球范围内,森林火灾已成为一个严重的生态和社会问题。它不仅对自然生态系统造成了毁灭性的影响,还对人类的生命财产安全构成了极大的威胁。根据国际森林发展组织的统计,全球每年因森林火灾造成的经济损失高达数百亿美元,甚至在某些年份,火灾损失占到某些国家国民经济总量的相当一部分。因此,开展高效的森林火情监测与早期预警工作显得尤为重要。随着科技的发展,无人机作为新兴的监测工具,以其高效、灵活和经济的特点在森林火灾监测领域展现出了巨大的潜力。

2502_92579126的博客 1212

【C++】函数模板(泛化,部分特化,完全特化)和模板函数

宏定义:在预编译期,进行简单的宏替换优点:代码复用性强缺点:缺少类型检查函数模板:用于泛型编程,(不考虑数据类型进行编程的方式)函数模板通常用:template声明开始进行泛型编程。typename用于声明泛指类型主要作用:提高代码的通用性。

weixin_52958292的博客 567

IP-Guard安全网关实例

企业相关情况: 1.OA系统,主要为日常工作使用,该系统IP为192.168.1.2,端口为8080; 2.文件共享服务器,用于存放日常工作资料和文档,该文件共享服务器的IP为192.168.1.1,其中\\192.168.1.1\private 目录中的存放着公司重要文档,不能随意外传; 3.安全网关已采用串联的方式联入网络,IP为192.168.2.6,所有机器访问OA系统和文件共享服务...

IP-Guard专栏 707

华为OD机试真题 Java&Go 实现【优雅子数组】【100%通过率】【2022.11 Q4 新题】

如果一个数组中出现次数最多的元素出现大于等于K次,被称为K -优雅数组,k也可以被称为优雅阈值。例如,数组1,2,3,1、2,3,1,它是一个3-优雅数组,因为元素1出现次数大于等于3次,数组1,2,3,1,2就不是一个3-优雅数组,因为其中出现次数最多的元素是1和2,只出现了2次。给定一个数组A和k,请求出A有多少子数组是k-优雅子数组。

MISAYAONE的博客 1万+

C++——函数模板

函数模板的定义 函数模板定义的一般形式如下: template<类型形式参数表> 返回类型 函数名(形式参数表) { //函数体 } template为关键字,表示定义一个模板,尖括号<>表示模板参数,模板参数主要有两种,一种是模板类型参数,另一种是模板非类型参数。上述代码中定义的模板使用的是模板类型参数,模板类型参数使用关键字class或typedef开始,其后是一个用户定义的合法标识符。模板非类型参数与普通参数定义相同,通常为一个常数。 可以将声明函数模板分成templ

weixin_50464560的博客 688

ASPICE学习笔记

ASPICE的全称是Automotive SPICE。

汽车电子软件领域知识分享 1355

C++函数模板

模板是一个通用框架,是C++泛型编程思想的主要体现。C++提供了函数模板和类模板两种模板机制,本文介绍的是函数模板相关的知识。

weixin_44205961的博客 5918

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

C++模板、类模板、函数模板详解都在这里了

C++模板、类模板、函数模板详解一、引言二、函数模板1、定义2、调用3、多个虚类型三、类模板1、定义2、调用四、类的函数模板五、类作为数据类型传入六、类模板与继承七、类模板与友元 一、引言 在写排序算法时,如果要写一个交换两个数据的函数,由于基本数据类型有int、float、double等等类型,所以针对每种数据类型可能我们要写很多swap函数,这些函数除了传入的数据类型不同,函数体结构大致相同。...

hsxyfzh的博客 1万+

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

C++函数模板及实现原理

C++为我们提供了函数模板机制。所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。 凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。     为什么要有函数模板     下面,我们就通过一个例子来说

常敲代码手不抖 2万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

cpp中的函数模板

之前我们讲了函数重载,对一个不同参数类型的函数作出了不同的行为,但是其实有一个更加高效的方式,那就是函数模板,也叫泛型编程。或者模板元编程。下面是一个交换两个元素的例子我们只需要在调用时指定类型就可以我们也可以指定两种类型,下面的程序没有什么实际意义,就是为了展示一下

Lyajpunov的博客 1434

C++函数模板的详细讲解【函数模板的概念、用法及其模板函数的概念知识】

目录前言C++函数模板的使用函数模板语法1.模板说明2.函数定义3.函数模板调用模板函数函数模板和函数重载 前言 C++提供了模板(template)编程的概念。所谓模板,实际上是建立一个通用函数或类,其类内部的类型和函数的形参类型不具体指定,用一个虚拟的类型来代表。这种通用的方式称为模板。模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。 C++函数模板的使用 为什么要有函数模板 例如,在一个项目中,有个项目需求是能够实现多个函数用来返回两个数的最大值,要求能支持char类型、int

m0_53636439的博客 5万+

C++ 函数模板基础

C++ 函数模板基础

英雄哪里出来 5074

C++编程——函数模板

文章目录1 函数模板语法2 函数模板注意事项3 函模模板案例4 普通函数与函数模板的区别5 普通函数与函数模板的调用规则6 模板的局限性 模板就是建立通用的模具,大大提高复用性 模板的特点: 模板不介意直接使用,它只是一个框架 模板的通用并不是万能的 C++另一种编程思想称为泛型编程,主要利用的技术就是模板 C++提供两种模板机制:函数模板和类模板 本文介绍的是函数模型的知识 1 函数模板语法 函数模板作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表 语法: te

professor_tao的博客 6176

Cpp--C++中函数模板的用法详细解析

C++中的模板可分为函数模板和类模板,而把函数模板的具体化称为模板函数,把类模板的具体化成为模板类。下面让我们分别看看什么是函数模板和类模板吧 1.什么是模板 假设现在我们完成这样的函数,给定两个数x和y求式子x^2 + y^2 + x * y的值 .考虑到x和y可能是 int , float 或者double类型,那么我们就要完成三个函数: int fun(

samkieth 806

C++ 函数模板

函数模板:通过模板参数定义通用函数,编译器根据实际参数类型生成具体函数实现。decltype:用于在编译时查询表达式的数据类型,不计算表达式的值。函数后置返回类型:允许将返回类型放在函数参数列表之后,适用于复杂类型推导。注意事项:包括模板参数的匹配、隐式类型转换、多个参数、模板重载等。函数模板的具体化:允许为特定类型提供函数模板的特定实现。通过这些概念和用法,你可以编写更灵活和强大的模板代码,处理各种复杂的类型和表达式。

qq_50373827的博客 1445
上一篇: C++之类继承和多态(虚函数、构造函数,析构函数)
下一篇: C++之类模板
Worthwhile_HUST
博客等级 码龄5年 53粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值