C++函数模板的隐式实例化、显式实例化与显式具体化

1、什么是实例化和具体化?ios

        为进一步了解模板,必须理解术语实例化和具体化。数组

        (1)、实例化:在程序中的函数模板自己并不会生成函数定义,它只是一个用于生成函数定义的方案。编译器使用模板为特定类型生成函数定义时,获得的是模板实例。这便是函数模板的实例化。函数

        而函数模板实例化又分为两种类型:隐式实例化和显式实例化spa

例如:指针


template < typename T >
void Swap( T &a, T &b )
{
      T temp;
      temp = a;
      a = b;
      b = temp;
}
int main(void)
{
        int a= 1, b = 2;
        Swap(a, b);
        Swap<int>(a, b);
        return 0;
}blog

        能够发现,在主函数中有两种Swap函数调用。原型

        第一个Swap(a, b)致使编译器自动识别参数类型生成一个实例,该实例使用int类型,此为隐式实例化。    编译器

        而第二个Swap<int>(a, b),直接命令编译器建立特定的int类型的函数实例,用<>符号指示类型,此为显式实例化。io

        (2)、具体化:即显式具体化,与实例化不一样的是,它也是一个模板定义,但它是对特定类型的模板定义。显式具体化使用下面两个等价的声明之一:编译

template <> void Swap<int>(int &, int &);
 
template <> void Swap(int &, int &);


        能够发现,显式具体化声明在关键字template后包含<>。上面声明的意思是"不要使用Swap()模板来生成函数定义,而应使用专门为int类型显式地定义的函数的定义"。这些原型必须有本身的函数定义。

         在这里,有人可能要说了:”明明能够经过隐式实例化自动生成int类型的函数定义,为什么还要弄出一个显式具体化来弄出另一个模板呢?这不是画蛇添足吗?”

        我要解释一下,显式具体化的主要用途!而在介绍用途以前,咱们先来了解一下普通函数模板的局限性。

2、模板的局限性

假设有以下模板函数:

template <typename T>
void fun(T a, T b)
{ ... }


一般,代码假定可执行哪些操做。例如,下面的代码假定定义了赋值。

a = b;
可是若是T为数组,这种假设将不成立!

一样,下面的语句假设定义了<

if ( a > b )
但若是T为结构,则该假设便不成立!

另外,为数组名定义了运算符 > ,但因为数组名是常量地址,所以它比较的是数组的地址,而这并非咱们所指望的操做。下面的语句假定为类型T定义了乘法运算符,但若是T为数组、指针或结构,这种假设便不成立:

T c = a * b;


       总之,编写的模板函数极可能没法处理某些类型。一般在C++中有一种解决方案是:运算符重载,以便能将其用于特定的结构或类。就是说一个类重载了运算符+以后,使用运算符+的模板即可以处理重载了运算符+的结构。

       可是,还有另一种解决方案:为特定类型提供具体化的模板定义(这就是显式具体化的主要用途)。

3、显式具体化

       假定定义了以下结构:

struct job
{
      char  name[40];
      double  salary;
      int  floor;
}


       另外,假设但愿可以交换两个这种结构的内容。原来的模板使用下面的代码来完成交换:

temp  =  a;
a = b;
b = temp;


       因为C++容许将一个结构赋给另外一个结构,所以即便T是一个job结构,上述代码也可适用。然而,若是只想交换salary和floor成员,而不交换name成员,则须要使用不一样的处理代码。但Swap() 的参数将保持不变(两个job结构的引用),所以没法使用模板的重载来提供其余代码(模板重载,模板的参数列表必须不一样)。这时,就得用显式具体化来实现这个需求。

       上面已经介绍过显式具体化的声明方式,咱们直接经过代码实例来看一下:

#include <iostream>
using namespace std;
 
//job结构
struct job
{
    char name[40];
    double salary;
    int floor;
};
 
//普通交换模板
template <typename T>
void Swap(T &a, T &b)
{
    T temp;
    temp = a;
    a = b;
    b = temp;
}
 
//job类型的显式具体化模板
template <> void Swap<job>(job &j1, job &j2)
{
    double t1;
    int t2;
 
    //交换salary
    t1 = j1.salary;
    j1.salary = j2.salary;
    j2.salary = t1;
 
    //交换floor
    t2 = j1.floor;
    j1.floor = j2.floor;
    j2.floor = t2;
}
 
int main(void)
{
    int inta = 1, intb = 2;
    job zhangSan = {"张三", 80000, 6};
    job liSi = {"李四", 60000, 4};
 
    cout << "inta = " << inta << " inta = " << intb << endl;
    cout << zhangSan.name << " , " << zhangSan.salary << " , " << zhangSan.floor <<endl; 
    cout << liSi.name << " , " << liSi.salary << " , " << liSi.floor <<endl; 
 
    Swap(inta, intb); //编译器将实例化普通模板的int类型函数
 
    Swap(zhangSan, liSi);  //编译器将实例化显式具体化模板job类型函数
 
    cout << "\n交换后:\n" << endl;
    cout << "inta = " << inta << " inta = " << intb << endl;
    cout << zhangSan.name << " , " << zhangSan.salary << " , " << zhangSan.floor <<endl; 
    cout << liSi.name << " , " << liSi.salary << " , " << liSi.floor <<endl;
    return 0;
}

运行截图:

           

在程序运行时匹配模板时,遵循的优先级是:

        具体化模板优先于常规模板,而非模板函数优先于具体化和常规模板。  

相关文章
相关标签/搜索