函数模板

来源:互联网 发布:编程是干什么的 编辑:程序博客网 时间:2024/06/03 20:30

什么是函数模板

我们指导函数的重载可以实现一个函数名多用,将功能相同或者类似函数用同一个名来定义。这样可以简化函数的调用形式,但是程序中,仍然需要分别定义每个函数。C++提供函数模板可以简化这个工程。函数模板是通用的函数描述,也就是说,它们使用泛型来定义函数,其中的泛型可以用具体的类型(如int或double)替换。

template <typename T>void swap(T &a, T &b) {    T tmp;    tmp = a;    a = b;    b = tmp;}

在C++98添加关键字typename之前,C++使用关键字class来创建模板。可以用class代替typename定义。

重载模板

和常规重载一样,被重载的模板的函数特征标必须不同。如原来的模板的特征标委(T &,T &),而新模板的特征标为(T[],T[],int)。注意,在后面一个模板中,最后一个参数的类型为具体类型(int),而不是泛型。并非所有的模板参数都是模板参数类型。

显式具体化

假设定义了如下结构:

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

另外,假设希望能够交换两个这种结构的内容。由于C++允许将一个结构赋给另一个结构,因此即使T是一个job结构,上述代码也使用。然而,假设只想交换salary和floor成员,则需要使用不同的代码。故我们使用显式具体化。
C++98中关于具体化的标准

  • 对于给定的函数名,可以有非模板函数、模板函数和显示具体化模板函数以及它们的重在版本。
  • 显示具体化的原型和定义应以template<>打头,并通过名称来指出类型。
  • 具体化优先于常规模板,而非模板函数优于具体化和常规模板。
    下面是用于交换jobs结构的非模板结构、模板函数和具体化的原型:
//非模板函数void swap(job &, job &);//常规模板template <typename T>void swap(T &, T &);//显式具体化template<>void swap<job>(job &, job &);//<job>可选

实例化和具体化

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

int i = 2, j = 3;swap(i, j);

在代码中包含函数模板本身并不会生成函数定义,它只是一个用于生成函数定义的方案。编译器使用模版为特定类型生成函数定义时,得到的是模板实例。函数调用swap(i,j)导致编译器生成swap()的一个实例,该实例使用int类型。模板并非函数定义,但使用int的模板实力是函数定义。这种实例化方式称为隐式实例化。
最初,编译器只能通过隐式实例化,来使用模板生成函数定义,但现在C++还允许显式实例化(explicit instantiation)。其语法是,声明所需的种类——用<>符号指示类型,并在声明前加上关键字template;

template void swap<int>(int , int);

该声明的意思是“使用swap()模板生成int类型的函数定义”,而显式具体化的声明意识是“不要使用swap()模板来生成函数定义,而应使用专门为int类型显式地定义地函数定义”。

C++11特性:decltype关键字

decltype与auto关键字一样,用于进行编译时类型推导,不过它与auto还是有一些区别。decltype地类型推导并不是向auto一样是从变量声明的初始化表达式获得变量的类型,而是总是以一个普通表达式作为参数,返回该表达式的类型,而且decltype并不会对表达式进行求值。

 int x = 4; decltype(x) y; //推导结果为inty的类型为int

假设有如下声明:

decltype(expression) var;

decltype推导四规则:

  1. 如果expression是一个没有括号括起的标识符,则var的类型与该标识符的类型相同,包括const等限定符。
  2. 如果expression是一个函数调用,则var的类型与函数的返回类型相同。
  3. 如果expression是一个左值,则var为指向其类型的引用。
  4. 如果前面的条件都不满足,则var的类型与expression的类型相同。

泛型编程中结合auto,用于追踪函数的返回值类型

template <typename _T1, typename _T2>auto gt(T1 x, T2 y)->decltype(T1+T2){    return T1+T2;}
0 0
原创粉丝点击