c++函数模板

发布于:2022-12-26 ⋅ 阅读:(324) ⋅ 点赞:(0)

目录

一、函数模板(泛型编程) 概念:

二、格式:

三、参数:

四、模板的调用方法:

五、注意事项:

六、普通函数与函数模板的区别:

七、函数模板的重载:

八、函数模板的特化:

九、多文件实现函数模板:

十、函数模板的嵌套:

十一、函数模板的非类型参数:


一、函数模板(泛型编程) 概念

用一个标志表示类型,此类型并非实际类型。可以独立于任何特定类型的编程,是c++比较重要的一部分。(如:ppt模板 ——是一种框架,需要自行填写内容,可以方便使用,不用重复定义,提高复用度)

二、格式:

                template<class T>  或者  template<typename T>

                返回值 函数名(参数) {函数体}

#include <iostream>
using namespace std;

//写一个函数模板交换两个任意类型变量的值
template< class T1,typename T2>
void fun(T1 &a,T2 &b)
{
    T1 temp = a;
    a  = b;
    b = temp;
    cout << "我是函数模板" << endl;
}

三、参数:

        template :声明创建模板;

        typename/class:表明后面的T是一个通用类型,或者称为虚拟类型;

        T:通用类型或者虚拟类型,(理解成类型)可以在函数中直接当做普通类型使用。

四、模板的调用方法:

        1.显式类型推导:函数名<实际类型1,实际类型2>(参数);

        2.隐式类型推导:函数名(参数);

int main(int argc, char *argv[])
{
    double a=12.23;
    double b=23.12;
    cout << "交换前 a=" << a << "\t"<< "b=" << b << endl;
    fun(a,b);       //隐式推导优先调用普通函数
    fun<double,double>(a,b); //显式推导优先调用函数模板
     cout << "交换后 a=" << a << "\t"<< "b=" << b << endl;
    return 0;
}

五、注意事项:

        1.显式类型推导的参数和推导的类型必须一致;

        2.如果有普通函数和模板函数构成重载,隐式类型推导优先调用普通函数,想优先调用模板函数,可以用显式类型推导省略实际类型的方式: 函数名<>(参数1,参数2);(如下图)

#include <iostream>
using namespace std;
//写一个函数模板交换两个任意类型变量的值
template< class T1,typename T2>
void fun(T1 &a,T2 &b)//函数模板重载1
{
    T1 temp = a;
                a  = b;
                b = temp;
        cout << "我是函数模板1" << endl;
}
template <class T1,class T2>
void fun(T2 &a,T1 &b)//函数模板重载2
{
    T2 temp = a;
                a  = b;
                b = temp;
        cout << "我是函数模板2" << endl;
}

void fun(double &a,double &b)//普通函数
{
    double temp = a;
                    a = b;
                    b = temp;
      cout << " 我是普通函数" << endl;
}
int main(int argc, char *argv[])
{
    double a=12.23;
    double b=23.12;
    cout << "交换前 a=" << a << "\t"<< "b=" << b << endl;
    fun(a,b);       //隐式推导优先调用普通函数
    fun<>(a,b); //显式推导优先调用函数模板
     cout << "交换后 a=" << a << "\t"<< "b=" << b << endl;
    return 0;
}

 

六、普通函数与函数模板的区别:

        1.普通函数只能与一种数据类型相匹配        而函数模板可以多种类型

        2.普通函数在编译时就会构建函数               而函数模板只有在调用时才会构建函数

        3.普通函数调用时可以自动类型转换            而函数模板调用时会指定类型

        4.普通函数在函数模板是隐式推导时优先级高于函数模板。

七、函数模板的重载:

        1.概念:和普通函数的重载相似,也是同一个作用域内函数名相同参数列表不同。

        2.定义:template<class T1,class T2> void temp(T1 a,T2 b);

                    template<class T1,class T2> void temp(T2 a,T1 b);

                    template<class T1> void temp(T1 a);

        3.注意:在函数参数顺序不同的重载中,实例化(即调用函数的时)时不可以是相同类型(相同类型则无法判断调用哪一个);

八、函数模板的特化:

        1.概念:为了解决函数模板的局限性(参数类型不是基本数据类型时),在定义函数模板的时候,直接确定T的类型,也就是特定的函数模板;

        2.格式:template <class T> 返回值  函数名(类名& 对象){ 函数体 }

        3.优先级:当传入的自定义类型与特化版本匹配,会优先使用特化版本;

        4.特化后 :只有当类型确定才可以使用自定义类型中的成员变量及成员方法等;

        5.应用场景:当需要对两个对象进行比较时就需要传入特化模板才可进行比较。

#include <iostream>
#include <string>
using namespace std;
class person//定义一个类
{
public:
    int age = 0;
    string name;
    person(int age,string name):age(age),name(name) {
    }
};

/***********定义一个比较的函数模板********/
template <class T>
bool cmp(T a,T b)
{
    if(a == b)
    {
        return true;
    }
    return false;
}
/*************定义一个特化函数模板**************/
template<class T>
bool cmp(person& a,person& b)
{
    if(cmp<int>(a.age,b.age) && cmp<string>(a.name,b.name))//调用定义的比较函数模板
    {
        return true;
    }
    return false;
}

int main(int argc, char *argv[])
{
    person a(10,"temp");
    person b(10,"temp");

    //打印比较的结果:结果为1则两个对象的age和name相等,0则表示不相等
    cout << cmp<person>(a,b) << endl;
    return 0;
}

九、多文件实现函数模板:

        1.定义:在函数模板中定义函数或者类的时候,不能把.h和cpp文件定义和申明分开。

        2.后果:编译时会出现连接错误(错误原因是:函数模板是在调用时确定的版本,而调用时.h中没有函数实现,出现连接错误,找不到函数体);

        3.解决方法:

                1.把声明和定义都写在xx.h头文件中;

                 2.把xx.h和xx.cpp文件删除一个,其中一个改为xx.hpp文件即可;

                 3.在main中#include <xxx.h>  和 #include <xx.cpp>。

十、函数模板的嵌套:

        定义:直接在函数模板中调用另一个模板即可(如下)

        注意:函数模板嵌套使用时两个函数模板的名字不能一样,不然无法识别。

#include <iostream>

using namespace std;
template <class T>
void fun(T &a)
{
    cout << "我是函数模板1" << endl;
}

template <class T>
void show(T &a)
{
    fun(a);
    cout << "我是函数模板2" << endl;
}

int main(int argc, char *argv[])
{
    int a=12;
    show(a);//调用show函数模板时在函数内部会调用fun函数模板
    return 0;
}

十一、函数模板的非类型参数:

        1.定义:模板参数不仅可以使类型,也可以是值。可以用特定的类型名(比如int)而非typename或者class表示非类型模板参数。当模板被实例化时,非类型模板参数会被一个值而不是类型替代。非类型模板参数

        2.格式:template <class T,基本数据类型 变量名>   返回值 函数名(T& 变量);

        3.如:template <class T,int size> 返回值 函数名(T & a){函数体}

        4.注意:上列中size是通过模板传入到函数中,可以当做普通变量使用;

                      非类型参数都是常量,在函数中不允许修改,只可以使用,定义非类型参数变量时候,需要加const。

         5.代码部分:

#include <iostream>
#define len(x) sizeof(x)/sizeof(x[0])
using namespace std;

//如下:利用非类型参数把数组的size大小传入到函数模板中,就可对其进行排序
template <class T,int len>
void Sort(T *a)
{
    for(int i=0;i<len;i++)
    {
       for(int j=i+1;j<len;j++)
        {
              if(a[i] < a[j])
                {
                  T temp=a[i];
                   a[i]=a[j];
                   a[j]=temp;
                 }
            }
      }
     for(int i=0;i<len;i++)
      {
            cout << a[i] <<"\t" ;
       }
       cout << endl;
}

int main(int argc, char *argv[])
{
    int arr[5]={2,45,2,55,5};
    const int len1=len(arr);//传入的变量需要用const修饰

    Sort<int,len1>(arr);
    return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到