【c++】函数模板

何为泛型编程呢?简单的说就是,我们按照特定语法写代码,然后让编译器去具体实现这些代码。而函数模板,就是让编译器按照调用时的实参自动生成相应的函数版本.

定义和使用函数模板

格式如下:

template<typename AnyType>
returnType functionName(argument-list){
// do something
}

其中templatetypename是关键字。

Tips:
在c++98之前c++是使用class关键字来定义模板的,而在c++98开始使用typename关键字定义模板了。
示例:
现在假设我们想写一个swap函数来交换两个数的值

#include <iostream>
#include<cstring>
#include"test_h.h"
using std::string ;
using std::cout;
using std::endl;
//function declaration 
template<typename T>
void swap(T& a,T& b);


int main(int argc, char** argv) {
    int i1=19;
    int i2=20;
    double d1=19.0;
    double d2=20.0;
    cout<<i1<<endl;
    cout<<i2<<endl;
    cout<<d1<<endl;
    cout<<d2<<endl;
    cout<<"after transform"<<endl;
    swap(i1,i2);
    swap(d1,d2);
    cout<<i1<<endl;
    cout<<i2<<endl;
    cout<<d1<<endl;
    cout<<d2<<endl;

}
//function definition 
template<typename T>
void swap(T& a,T& b){
    T temp;
    temp=a;

    a=b;
    b=temp;

}

编译器会根据swap()中的参数类型自动生成int和double版本的函数。

Node:
记住template在定义和声明中都是不能少的

模板函数使用的局限性

假设有如下模板

template<typename T>
void f(T a,T b){
//……
}

如果a,b是数组的话a=b是不可以的
如果a,b是结构的话a>b也是不可以的
所以模板编程有时候你要考虑一下参数的特殊性。这时候我们就要用到显示具体化

函数模板显式具体化

格式如下:

template <>returnTyoe function< Type>(Type, Type)

其中template <>为关键字,如果编译器可以根据参数列表推断模板类型那么< Type>中的Type为可选项

示例:

void swap(int a,int b);

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

template<typename T>
void swap(T, T);

上卖弄三种分别为非模板函数,模板的显式具体化,模板函数

如果程序中同时定义了三种函数,会优先调用非模板函数,然后模板的显式具体化,最后模板函数

函数实例化

一开始定义的模板函数swap(T a,T b)它会告诉编译器生成函数的方式,但是还没有生成函数,而当调用swap(i1,i2)和swap(d1,d2)时就会生成相应的模板实例。模板的显式具体化也一样都是不会生成函数实例的,而是出现了具体类型之后再让编译器按照模板具体化创建函数实例。

在以前c++只能通过判断函数参数来实例化函数,这种叫做隐式实例化而现在的c++可以通过显式实例化了,格式如下

template returnType function<Type>(Type,Type);

上面的代码告诉编译器创建一个接受Type类型函数的实例,其中template为关键字,必须要写的。
示例:


template void swap<int>(int,int);//函数实例化

template<> void swap<int>(int,int);//模板具体化

上面的实例化告诉编译器使用swap模板生成一个接受int参数的函数实例,他已经在代码中了。
而模板显式具体化,告诉编译器当调用函数时如果参数为int时,就按照模板具体化定义的形式创建函数。

除了上面的显示实例化的手段,我们还可以在程序中手动使用函数模板来创建显示实例化,如下

template<typename T>
void swap(T a,T b){
    T temp;
    temp=a;

    a=b;
    b=temp;

}
……
int i=19;
double d=19.0;
cout<<swap<double>(i,d)<<endl;//fun(Type)来显示创建函数实例

上卖弄的模板函数与swap(i,d)是不匹配的,因为两个参数是不同的,但是通过显式实例化swap(i,d)来用模板 swap(T a,T b)创建double版本的函数,然后int的值会自动转换为double,以便函数使用

函数模板的调用

当同时有非模板函数,模板函数,模板显示具体化时定义时。会优先调用非模板函数,然后模板的显示具体化,最后模板函数

void f(int);                //#1  

float f(float,float=3);         //#2  

void f(char)                //#3  

char * f(const char *)          //#4  

char f(const chat *)            //#5  

template <class T>void f(const T &)   //#6  

template <class T>void fT *)    //#7

如果调用
f('B')
上面#3,#5,#6都是原型匹配,但是#3,#5优先于#6,#6优先于#1

decltype

template<typename T>
void f(T a,T b){


    ab=a+b;//ab是什么类型的呢?
}

所以c++11引入了关键字decltype来解决这个问题

int x;
decltype(x) y;//y is int
decltype(x+y) xy;//xy is x+y type
xy=x+y;
decltype(x+y)xy=x+y;//xy is x+y type

上面是三种decltype的简单使用。而对于如下标准格式
decltype(expression) var;
编译器会编译一个核对表,核对表的简化版如下
第一步:如果expresssion是一个没有用括号的标识符,则var的类型与该标识符相同,包括const等修饰符

double x=19.0;
double y=19.0
double &rx=x;
const double *pd;
decltype (x) w;//w is double
decltype (rx) u;
//u is double &
decltype (pd) v ;
//v const double *

第二步:如果experssion是一个函数调用,var是的类型与函数返回值一样

int f(int);
decltype(   f(3)) m//m is int

Note:
这实际不会调用函数,编译器会根据函数原型判断返回值类型
第三步:如果expression是一个左值,则var为指向类型的引用。这好像意味着前面w应为引用类型,因为x是一个左值,但是这种情况下已经在第一步处理过了。要进入第三步expression不能是未用括号括起来的标识符

double xx=19.0;
decltype((xx))r2=xx;//r2 is double &
devltype(xx)w=xx//w is double

第四步:如果前面条件都不满足,则var的类型与expression类型相同

int j=3;
int& k=j;
int& n=j;
decltype(j+6) i1;//i1 is int
decltype(100L) i2;
//i2 is long
decltype(k+n) i3;
//i3 is int 

c++11后置返回类型

template<typename T>
Type f(T a,T b){
    return a+b;//a+b的返回上什么类型呢?
}

decltype (a+b) 不行吗?因为这时候还没有定义a,b,编译器不知道a,b是什么。c++11为auto新增了语法功能来解决这个问题,如下
auto f(int i1,int i2)->double;
auto告诉编译器返回类型在后面写着。他可以和decltype 连用
auto f(int i1,int i2)->decltype(x+y);

这样就完成了返回类型的自动换了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值