c++中的函数模版

文章介绍了C++中的函数模板,包括什么是函数模板、如何定义和实例化,强调了模板参数的作用,指出函数模板在处理不同类型数据时的灵活性,并讨论了函数模板的默认实参和重载。示例代码展示了模板在解决最大值问题上的应用,同时对比了函数模板与宏定义的区别。
摘要由CSDN通过智能技术生成

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数C初学者入门训练题解CC的使用文章「初学」C++

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

🐰函数模版

🌸函数模版

🌸定义函数的一般模版

🌸函数模版的实例化

🌸函数模版参数

🌸🌸函数模版默认实参

🌸函数模版的重载


🐰函数模版

利用宏可以实现各种数据类型求最大值问题,但是宏一般简单的文本替换, 宏定义无法声明返回值的类型 如果宏运算的结果赋值给一个与之类型不匹配的变量,编译器并不能检查出错误
#include<iostream>
using namespace std;
#define MAX(x,y) (x>y?x:y)
int main()
{
    cout<<MAX(1,2)<<endl;
    cout<<MAX(1,2.1)<<endl;
    cout<<MAX(1.9,2.4)<<endl;
    return 0;
}
结果:
2
2.1
2.4

🌸函数模版

所谓的函数模版,实际上是建立在一个通用的函数,其函数类型和形参类型中的全部或部分类型不具体指定,用一个虚拟的类型来表示 这个通用的函数就是函数模版 凡是函数体相同的函数都可以用这个模版来代替,就不用定义多个函数了,只需在模版中定义一次即可 。在函数调用时系统会根据实参的类型来取代模版中虚拟的类型,从而实现不同的函数功能。
函数模版的定义:
#include<iostream>
using namespace std;
声明函数模版,其中T为类型参数
template<typename T>
T Max(T a,T b)//求两数中最大值
{
    return a>b?a:b;
}
int main()
{
    int a=3,b=5,m;
    short c=7,d=8,n;
    double e=1.2,f=4.5,p;
    m=Max(a, b);
    n=Max(c, d);
    p=Max(e, f);
    cout<<m<<" "<<n<<" "<<p<<endl;
    return 0;
}
结果:
5 8 4.5

🌸定义函数的一般模版

template<typename T>
返回类型 函数名(形参表)
{
    函数体;
}
或者
template<class T>
返回类型 函数名(形参表)
{
    函数体;
}

template是定义模版的关键字,尖括号先写关键字typename(或class),后面跟一个参数类型T(T就是一个名字,也可以是其他的A,B,a...)这个类型参数实际上是一个虚拟的类型名,表示模版中出现的T是一个类型名,但是现在并未指定它是哪一种具体类型。在函数定义时用T来定义变量x和y,显然变量x和y的类型也是未确定的。要等到函数调用时根据实参的类型来确定T是什么类型。参数名T由我们自己定义,其实也可以不用T而用任何一个标识符,许多人习惯于T,而且用大写,以与实际的类型名相区别。

class和typename的作用相同,都是表示它后面的参数名代表一个潜在的内置或用户定义的类型,二者可以互换。
注意:

(1)在定义模版时,不允许template语句与函数模版之间有任何其他语句

例如:

template<typename T>
int a;//template语句与函数模版之间有任何其他语句,
T Add(T a,T b)
{
    ...
};
(2)不要把这里的class与类的声明关键字class混淆在一起,虽然它们由相同的字母组成,但是含义是不同的。为了区别类与模版中的关键字class,标准C++提出了用typename作为模版参数的类型关键字,同时也支持使用class。
(3)函数模版的类型参数可以有多个,可根据实际需求确定个数,但每个类型参数都必须用关键字typename或class限定,例如
template<typename T1,typename T2,typename T3...>
T1 Func(T2 a1,T3 a2,...)
{
    ...
}
(4)当一个名字被声明为模版参数后,它就可以使用了,一直到模版声明或定义结束为止 。模版参数被用作一个类型指示符,可以出现在模版定义的余下部分
(5)函数模版的定义通常放到头文件中

🌸函数模版的实例化

当编译器遇到关键字template和跟随其后的函数定义时,它只是简单地知道,这个函数模版在后面的程序代码中可能会使用到。除此之外,编译器不会做额外的工作。在这个阶段,函数模版本身并不能使编译器产生任何代码,因为编译器并不知道函数模版要处理的具体数据类型。

当编译器遇到程序中对函数模版的调用时,它才会根据调用语句实际参数的具体类型,确定模版参数的数据类型,并用此类替换函数模版中的模版参数,生成能够处理该类型的函数代码。

由此可见。函数模版比使用函数重载更方便。但它只适用于函数的参数个数相同而类型不同,且函数体相同的情况下,如果参数个数不同,则不能用函数模版

🌸函数模版参数

C++在实例化函数模版的过程中,只是简单地将模版参数替换成调用实际参数类型,并以此生成模版函数,不会进行参数类型的任何转换。这种方式与普通函数处理有着很大的区别,在普通函数的调用过程中,C++会对类型不匹配的参数进行隐式转换。

例如:

#include<iostream>
using namespace std;
int Max1(int a,int b)
{
    return  a>b?a:b;
}
int main()
{
    cout<<"两数中最大数为:"<<endl;
    cout<<Max1(2, 3.8)<<endl;//因为Max1不是模版函数,而是普通的函数,虽然传入的两个数据的类型不同,一个为整形,一个为浮点型,但是函数会对传进来的实际参数进行进行隐式转换
    cout<<Max1('a', 3.8)<<endl;//这里的'a'会转换为'a'的ASCII值
    return 0;
}
结果:
两数中最大数为:
3
97
#include<iostream>
using namespace std;
template<typename T>
T Max(T a,T b)
{
    return a>b?a:b;
}
int main()
{
    cout<<"两数中最大数为:"<<endl;
    cout<<Max(3.4,2)<<endl;
    
}

以上代码程序编译时会报错,基模版参数不匹配。产生这种类型错误的原因就是模版实例化时,C++不会进行任何形式的参数类型的转换。上述代码,它首先调用实参的函数模版T Max(T a,T b),生成模版函数。由于Max(3.4, 2)的调用实参类型分别为double和int,而函数模版只有一个模版参数T,因此,这个调用与模版声明不匹配。

解决方法:
(1)在模版调用时进行参数的强制类型的转换
cout<<Max((int)(3.4), 2);

(2)通过提供"<>"里的参数类型来调用这个模版

cout<<Max<int>(3.4, 2);
cout<<Max<double>(3.4, 2);

(3)指定多个模版参数

#include<iostream>
using namespace std;
template<typename T,typename R>
T Max(T a,R b)
{
    return  a>b?a:b;
}
int main()
{
    cout<<"两数中最大数为:"<<endl;
    cout<<Max(3.4, 2);
    return 0;
}

注意:
模版参数可以出现用typename或class关键字声明的类型参数除外,还可以出现确定类型参数,称为非类型参数,例如
template<typename T1,typename T2,typename T3,int temp>
T1 Func(T1 a,T2 b T3 c){...}

temp:模版非类型参数名代表了一个潜在的值。他被用做一个常量值,可以出现在模版定义的余下部分。他可以用在要求常量的地方。在模版调用时只能为其提供相应类型的常数值。非类型参数是受限制的,通常可以是整形,枚举型,对象或函数的引用,以及对象、函数或类成员的指针,不许许是类对象、浮点型或void作为非类型参数。

🌸🌸函数模版默认实参

函数模版也可以提供默认实参

🌸函数模版的重载

就像普通函数一样,也可以重载函数模版
#include<iostream>
using namespace std;
template<typename T>
T Max(T a,T b)//计算两个数的最大值
{
    return a>b?a:b;
}
template<typename T>
T Max(T a,T b,T c)//计算三个数的最大值
{
    return Max(Max(a,b),c);//这里调用了计算两个数的最大值的函数
}
int main()
{
    int a=5,b=6,c=7;
    cout<<"两数的最大值为:"<<endl;
    cout<<Max(a, b)<<endl;
    cout<<"三个数的最大值为:"<<endl;
    cout<<Max(a, b,c)<<endl;
    return 0;
}
结果:
两数的最大值为:
6
三个数的最大值为:
7

有多个重载函数,其中包括普通函数和函数模版,系统首先寻找一个参数完全匹配的普通函数,如果找到了就调用它;如果找不到,再寻找函数模板,使其实例化,产生一个完全匹配的模板函数。

#include<iostream>
#include<cstring>
using namespace std;
template<class T>
T mymax(T a,T b)
{
    cout<<"函数模板"<<endl;
    return a>b?a:b;
}
int mymax(int a,int b)
{
    cout<<"函数(1)"<<endl;
    return a>b?a:b;
}
const char* mymax(const char*  e1,const char*  e2)
{
    cout<<"函数(2)"<<endl;
    return strcmp(e1, e2)>0?e1:e2;
}
int main()
{
    cout<<mymax(1, 2.3)<<endl;
    cout<<mymax(1.2, 2.3)<<endl;
    cout<<mymax("abc","b")<<endl;
    return 0;
}
结果:
函数(1)
2
函数模板
2.3
函数(2)
b

 🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸  

函数模板是一种通用的函数定义,它允许编写能够处理多种不同类型的数据的函数函数模板的定义以关键字 `template` 开头,后面跟着模板参数列表和函数的原型。 例如,以下是一个简单的函数模板,用于交换两个值: ```c++ template <typename T> void swap(T& a, T& b) { T temp = a; a = b; b = temp; } ``` 上述代码,`typename T` 表示这是一个类型参数,可以接受任何类型的数据。在函数,我们只是简单地交换了两个值。 使用函数模板时,需要将具体的类型传递给模板参数,例如: ```c++ int a = 5, b = 10; swap<int>(a, b); // 交换 a 和 b 的值 ``` 在上述示例,我们显式地将 `int` 作为模板参数传递给 `swap` 函数函数模板还支持全特化,这意味着我们可以为特定的类型提供一个特定的实现。全特化使用关键字 `template<>` 手动指定模板参数列表的类型,并提供一个特定的函数实现。 例如,以下是一个针对 `char` 类型的 `swap` 函数的全特化: ```c++ template <> void swap<char>(char& a, char& b) { char temp = a; a = b; b = temp; std::cout << "Swapping chars!" << std::endl; } ``` 上述代码,我们使用了 `template<>` 关键字显示地声明了一个全特化函数,指定了模板参数为 `char`。 当我们调用 `swap` 函数,并将 `char` 类型的变量作为参数传递时,编译器将自动选择调用这个全特化版本的函数。 需要注意的是,全特化版本的函数应该在头文件进行声明和定义,以便编译器能够正确地实例化这些函数
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值