zoukankan      html  css  js  c++  java
  • 函数模板

    1、为什么引入函数模板?

    考虑下面两个需求:

    • 交换两个整型变量的值的Swap函数:
    void Swap(int & x,int & y)
    {
    	int tmp = x;
    	x = y;
    	y = tmp;
    }
    
    • 交换两个double型变量的值的Swap函数:
    void Swap(double & x,double & y)
    {
    	double tmp = x;
    	x = y;
    	y = tmp;
    }
    

    上述代码有着明显的重复。考虑一个问题:能否只写一个Swap,就能交换各种类型的变量?(即:提高代码的重用性)

    2、解决问题的方案:引入函数模板

    (1)定义模板的语法:
    template <class 类型参数1,class 类型参数2,......>
    返回值类型 模板名 (形参表)
    {
    	函数体
    };
    

    (2)针对上述问题,可以定义函数模板:

    template <class T>
    void Swap(T & x,T & y)
    {
    	T tmp = x;
    	x = y;
    	y = tmp;
    }
    

    编译器会在函数调用语句处,自动根据函数模板实参类型生成一个函数。由模板生成的函数被称为模板函数

    3、举栗子。

    (1)例1,函数模板可以不止有一个类型参数
    template <class T1, class T2>
    T2 print(T1 arg1, T2 arg2)
    {
    	cout<< arg1 << " "<< arg2<<endl;
    	return arg2;
    }
    
    (2)例2,求数组最大元素的MaxElement函数模板
    template <class T>
    T MaxElement(T a[], int size) //size是数组元素个数
    {
    	T tmpMax = a[0];
    	for( int i = 1;i < size;++i)
    	if( tmpMax < a[i] )
    	tmpMax = a[i];
    	return tmpMax;
    }
    

    4、实例化函数模板的两种方式

    (1)方式一:通过参数实例化(隐式实例化)

    注意:匹配模板函数时,不进行类型自动转换。

    template<class T>
    T myFunction( T arg1, T arg2){ 
    	cout<<arg1<<" "<<arg2<<"
    "; 
    	return arg1;
    }
    void main(){
    	myFunction( 5, 7); 		//ok:replace T with int
    	myFunction( 5.8, 8.4); 	//ok: replace T with double
    	myFunction( 5, 8.4); 	//error,no matching function for callto 'myFunction(int, double)'
    }
    
    (2)方式二:不通过参数实例化函数模板(显式实例化)

    举栗:

    #include <iostream>
    using namespace std;
    template <class T>
    T Inc(T n)
    {
    	return 1 + n;
    }
    int main()
    {
    	cout << Inc<double>(4)/2;
    	return 0;
    }
    

    考虑:是否支持参数隐式转换?

    4、模板重载

    函数模板可以重载,只要它们(它们指的是:实例化出来的函数)的形参表或类型参数表不同即可。

    template<class T1, class T2>
    void print(T1 arg1, T2 arg2) {
    	cout<< arg1 << " "<< arg2<<endl;
    }
    template<class T>
    void print(T arg1, T arg2) {
    	cout<< arg1 << " "<< arg2<<endl;
    }
    template<class T,class T2>
    void print(T arg1, T arg2) {
    	cout<< arg1 << " "<< arg2<<endl;
    }
    

    5、函数模板和函数的次序

    在有多个函数和函数模板名字相同的情况下,编译器如下处理一
    条函数调用语句:

    • 先找参数完全匹配的普通函数(非由模板实例化而得的函数)。
    • 再找参数完全匹配的模板函数。
    • 再找实参数经过自动类型转换后能够匹配的普通函数。
    • 上面的都找不到,则报错。

    举栗子:

    template <class T>
    T Max( T a, T b) {
    cout << "TemplateMax" <<endl;
    return 0;
    }
    template <class T,class T2>
    T Max( T a, T2 b) {
    	cout << "TemplateMax2" <<endl;
    	return 0;
    }
    double Max(double a, double b){
    	cout << "MyMax" << endl;
    	return 0;
    }
    int main() {
    	int i=4, j=5;
    	Max( 1.2,3.4); // 输出MyMax
    	Max(i, j); //输出TemplateMax
    	Max( 1.2, 3); //输出TemplateMax2
    	return 0;
    }
    

    6、函数模板示例:Map

    #include <iostream>
    using namespace std;
    template<class T,class Pred>
    void Map(T s, T e, T x, Pred op)
    {
    	for(; s != e; ++s,++x) {
    		*x = op(*s);
    	}
    }
    int Cube(int x) {
    	return x * x * x; 
    }
    double Square(double x) {
    	 return x * x; 
    }
    
    int a[5] = {1,2,3,4,5}, b[5];
    double d[5] = { 1.1,2.1,3.1,4.1,5.1} , c[5];
    int main() {
    	Map(a,a+5,b,Square);
    	for(int i = 0;i < 5; ++i) cout << b[i] << ",";
    	cout << endl;
    	Map(a,a+5,b,Cube);
    	for(int i = 0;i < 5; ++i) cout << b[i] << ",";
    	cout << endl;
    	Map(d,d+5,c,Square);
    	for(int i = 0;i < 5; ++i) cout << c[i] << ",";
    	cout << endl;
    	return 0;
    }
    /*输出:
    1,4,9,16,25,
    1,8,27,64,125,
    1.21,4.41,9.61,16.81,26.01,
    */
    
    

    实例化函数解释:

    //函数模板
    template<class T,class Pred>
    void Map(T s, T e, T x, Pred op) {
    	for(; s != e; ++s,++x) {
    		*x = op(*s);
    	}
    }
    //实例化的模板函数
    void main(){
    	int a[5] = {1,2,3,4,5}, b[5];
    	Map(a,a+5,b,Square); //实例化出以下函数:
    }
    
    void Map(int * s, int * e, int * x, double ( *op)(double)) {
    	for(; s != e; ++s,++x) {
    		*x = op(*s);
    	}
    }
    
  • 相关阅读:
    more命令
    mktemp命令
    有效的括号字符串
    mc命令
    字符串相加
    Vue中虚拟DOM的理解
    chattr命令
    记近一年线上项目经验及架构变更记录
    微博AnalysisQl动态数据视图元数据设计
    搭建prometheus+grafana监控SpringBoot应用入门
  • 原文地址:https://www.cnblogs.com/lasnitch/p/12764232.html
Copyright © 2011-2022 走看看