C++ 之函数模板详解

模板函数详解

一、 模板实参和模板函数的概念

1.1模板实参
什么是模板实参?
以下面这个函数为例:

//交换x和y函数
template <class T>
void Swap(T & x, T & y)
{
    T tmp = x;
    x = y;
    y = tmp;
}

定义时T 是类型参数,代表类型。编译器由模板自动生成函数时,会用具体的类型名对模板中所有的类型参数进行替换,其他部分则原封不动地保留。同一个类型参数只能替换为同一种类型。编译器在编译到调用函数模板的语句时,会根据实参的类型判断该如何替换模板中的类型参数。

函数模板的数据类型参数标识符实际上是一个类型形参,在使用函数模板时,要将这个形参实例化为确定的数据类型。将类型形参实例化的参数称为模板实参,用模板实参实例化的函数称为模板函数。模板函数的生成就是将函数模板的类型形参实例化的过程。

1.2、函数模板(Function Template)
什么是函数模板?
所谓函数模板,实际上就是建立一个通用函数
1、函数定义时不指定具体的数据类型(使用虚拟类型代替)
2、函数被调用时编译器根据实参反推数据类型-类型的参数化
函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计。它的最大特点是把函数使用的数据类型作为参数。

什么使模板函数?
模板函数:函数模板的数据类型参数标识符实际上是一个类型形参,在使用函数模板时,要将这个形参实例化为确定的数据类型。将类型形参实例化的参数称为模板实参,用模板实参实例化的函数称为模板函数。模板函数的生成就是将函数模板的类型形参实例化的过程。

函数模板与模板函数的关系
函数模板经实例化而生成的具体函数称为模板函数
函数模板代表了一类函数。
模板函数表示某一具体函数。

函数模板的声明形式为:

template<typename 数据类型参数标识符>
<返回类型><函数名>(参数表)
{
函数体
}

/*********************************************/

//模板头与函数声明/定义永远是不可分割的整体!
template<typename 类型参数1typename 类型参数2...>//typename老版C++用class
返回值类型 函数名(形参列表){
    //函数体中可以使用类型参数
}

补充:

template<typename T>
template<class T>  //早期写法

例:定义排序函数

#include
using namespace std;

template<typename T> void Sort(T tArray[],int len);

int main()
{
    int a[]={10 ,55,11,59,15};
    Sort(a,5);
    for(int i=0;i<5;i++)
    {
        cout<<a[i]<<" ";
    }
    return 0;
}
template<typename T> void Sort(T tArray[],int len)
{
    for(int i=0;i<len-1;i++)
    {
        for(int j=0;j<len-i-1;j++)
        {
            if(tArray[j]>tArray[j+1])
            {
                T temp=tArray[j];
                tArray[j]=tArray[j+1];
                tArray[j+1]=temp;
            }
        }
    }
}

二、函数模板与重载

2.1函数模板不代替重载
模板函数类似于重载函数,但两者有很大区别:函数重载时,每个函数体内可以执行不同的动作,但同一个函数模板实例化后的模板函数都必须执行相同的动作。也就是说:
重载函数各函数体内可以执行不同的代码,但同一个函数模板实例化的不同模板函数都执行相同的代码,仅仅是处理的数据类型不同而已。

2.2模板函数与同名的非模板函数重载时,调用的顺序
当函数模板与一般函数同名时,遵循下面的调用顺序:
(1)一个函数调用首先寻找参数完全匹配的一般函数,如果有就调用它。
(2)寻找一个函数模板,使其实例化,生成一个匹配的模板函数,然后调用该模板函数。
补充描述:
就像一般的重载函数一样,重新定义一个完整的非模板函数,它所带的参数可以随意。C++中,函数模板与同名的非模板函数重载时,应遵循下列调用原则:
• 寻找一个参数完全匹配的函数,若找到就调用它。若参数完全匹配的函数多于一个,则这个调用是一个错误的调用。
• 寻找一个函数模板,若找到就将其实例化生成一个匹配的模板函数并调用它。
• 若上面两条都失败,则使用函数重载的方法,通过类型转换产生参数匹配,若找到就调用它。
•若上面三条都失败,还没有找都匹配的函数,则这个调用是一个错误的调用。


三、总结

什么是模板实参和模板函数?
答:函数模板的数据类型参数标识符实际上是一个类型形参,在使用函数模板时,要将这个形参实例化为确定的数据类型。将类型形参实例化的参数称为模板实参,用模板实参实例化的函数称为模板函数。而函数模板是可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计。它的最大特点是把函数使用的数据类型作为参数。

模板函数与同名的非模板函数重载时,调用的顺序是怎样的?
答:当函数模板与一般函数同名时,遵循下面的调用顺序:一个函数调用首先寻找参数完全匹配的一般函数,如果有就调用它。寻找一个函数模板,使其实例化,生成一个匹配的模板函数,然后调用该模板函数。

你可能感兴趣的:(C++)