模板函数基础(函数模板)

基本模板函数示例

不会使用函数模板的时候,一般情况下,我们要交换两个变量的值,我们会写下面的代码:

//如果交换的两个值是整型变量
void myswap(int &a, int &b)
{
    int temp;
    temp = a;
    a = b;
    b = temp;
}

//如果交换的两个值是浮点型变量
void myswap(double &a, double &b)
{
    double temp;
    temp = a;
    a = b;
    b = temp;
}

明明大部分代码是一样的,写两遍并不是一个优秀程序员的做法,使用模板函数可以提高代码的重用性。

在使用模板函数的情况下,代码可以简化为这样:

//模板函数,类型参数化,编写模版代码时可以忽略类型
//一个“template”只对一个函数生效
#include<iostream>
using namespace std;
template<class T>	//告诉编译器,我下面写的是模板函数
	void myswap(T &a, T &b)
	{
   	 	T temp;
    	temp = a;
    	a = b;
   	 	b = temp;
	}
int main()
{
    int a = 10, b = 20;
    cout << a << " " << b << endl;
    myswap(a, b);		//这里就不需要考虑a,b的类型了
    cout << a << " " << b << endl;
    double c = 13.4, d = 7.32;
    cout << c << " " << d << endl;
    myswap(c, d);
    cout << c << " " << d << endl;
    return 0;
}

输出的结果应该是:

10 20
20 10
13.4 7.32
7.32 13.4

template的参数可以不止一个:

//而template<这里可以填写多个数据>
template<class T1, class T2>
	void myswap(T1 &a, T1 &b, T2 c)
	{
	    T1 temp;
	    temp = a;
	    a = b;
    	b = temp;
    	cout << c << endl;
	}

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

  • 模版函数不允许自动类型转化
  • 普通函数能够进行自动类型转化
  • 模板函数必须严格类型匹配
#include<iostream>
using namespace std;
template<class T>
    int myadd(T a, T b)
    {
        return a+b;
    }
int myadd(int a, char b)
{
    return a+b;
}
int main()
{
    int a=10, b=20;
    char c1='a', c2='b';
    
    myadd(a, c1);	//调用的是普通函数
    myadd(a, b);	//调用的是模板函数
    myadd(c1, b);	//调用的是普通函数
    
    return 0;
}

模板函数和普通函数一起使用的规则

  • 模板函数可以像普通函数那样进行函数重载
  • c++编译器会优先考虑普通函数
  • 如果模板函数可以产生一个更好的匹配,那么将选择模板函数
  • 可以通过空模板实参列表的语法限定编译器,实现只能通过模板匹配
#include<iostream>
using namespace std;
template<class T>
	void Print(T a, T b)
	{
    	cout<<a+b<<endl;
    	cout<<"这是模板函数"<<endl;
	}
void Print(int a, int b)
{
    cout<<a+b<<endl;
    cout<<"这是普通函数"<<endl;
}
int main()
{
    int a=10, b=20;
	Print(a, b);	//c++编译器会优先考虑普通函数
    return 0;
}

虽然a,b的值既符合普通函数又符合模板函数,但会优先考虑普通函数,代码结果如下:

30
这是普通函数

如果就是想调用模板函数的话,可以写 Print<>(a, b); 的形式

一般不这样做,除非有特别的需求。具体如下:

#include<iostream>
using namespace std;
template<class T>
	void Print(T a, T b)
	{
    	cout<<a+b<<endl;
    	cout<<"这是模板函数"<<endl;
	}
void Print(int a, int b)
{
    cout<<a+b<<endl;
    cout<<"这是普通函数"<<endl;
}
int main()
{
    int a=10, b=20;
	Print<>(a, b);	//c++编译器会优先考虑普通函数
    return 0;
}

代码结果如下:

30
这是模板函数

模板函数的实现原理剖析

  • 要分清楚模板函数和函数模板的区别

函数模板 —— 是一种模板,用于生成函数的模板

模板函数 —— 是一种函数,通过“函数模板”生成的函数

//函数模板(类似于加工厂的模具,无法直接使用)
template<class T>
int myadd(T a, T b)
{
    retrun a+b;
}

//首先会生成一个模板函数(类似于加工好的零件)
//比如说,用两个float型变量调用的就会生产这样的函数
int myadd(float a, float b)
{
    retrun a+b;
}

//最后才会被编译器调用

看一下在接下来的程序(包含函数模板),会生成多少个模板函数?

#include<iostream>
using namespace std;
template<class T>
int myadd(T a, T b)
{
    retrun a+b;
}
int main()
{
    int a=10, b=20, c=25;
    float c=4.27, d=21.75;
    myadd(a, b);	//此时会产生“模板函数1”
    myadd(c, d);	//此时会产生“模板函数2”
    myadd(b, c);
    return 0;
}

没错,会生成以下两种模板函数

//“模板函数1”
int myadd(int a, int b)
{
    retrun a+b;
}

//“模板函数2”
int myadd(float a, float b)
{
    retrun a+b;
}

函数模板机制结论:

  • 编译器并不是把函数模板处理成能够处理任何类型的函数
  • 而是作为一个模板,通过具体类型产生不同的函数
  • 编译器会对模板函数进行二次编译,第一次是在声明的地方对函数模板代码本身进行编译,第二次是在调用时对参数替换后的代码进行编译

函数模板的使用实例

利用冒泡排序对一串数字和字母排序:

#include<iostream>
using namespace std;
template<class T>
void Print(T* a, int len)
{
    for (int i = 0; i < len; i++)
        cout << a[i] << " ";
    cout << endl;
}
template<class T>
void Sort(T* a, int len)
{
    if (len < 2)
        return;
    T temp;
    bool flag;
    for (int i = 0; i <len-1; i++)
        {
            flag = 0;
            for (int j = 0; j < len - i - 1; j++)
                if (a[j] > a[j + 1])
                {
                    temp = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = temp;
                    flag = 1;
                }
            if (flag = 0)
                break;
        }
}
int main()
{
    int a[] = { 2,7,4,9,1,3,6 };
    int len = sizeof(a) / sizeof(a[0]);
    Print(a, len);
    Sort(a, len);
    Print(a, len);
    char b[] = { 'd','f','r','v','a','u' };
    len = sizeof(b) / sizeof(b[0]);
    Print(b, len);
    Sort(b, len);
    Print(b, len);
    return 0;
}

其输出的结果是:

2 7 4 9 1 3 6
1 2 3 4 6 7 9
d f r v a u
a d f r u v

而且只需要写一遍冒泡排序的代码,就可以实现数字和字母两种不同类型的排序。

以上是对模板函数初步解析,欢迎大家在评论区提出问题进行探讨!

  • 13
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值