【c++】函数模板
2017-02-03 18:49
274 查看
何为泛型编程呢?简单的说就是,我们按照特定语法写代码,然后让编译器去具体实现这些代码。而函数模板,就是让编译器按照调用时的实参自动生成相应的函数版本.
其中template和typename是关键字。
Tips:
在c++98之前c++是使用class关键字来定义模板的,而在c++98开始使用typename关键字定义模板了。
示例:
现在假设我们想写一个swap函数来交换两个数的值
编译器会根据swap()中的参数类型自动生成int和double版本的函数。
Node:
记住template在定义和声明中都是不能少的
如果a,b是数组的话
如果a,b是结构的话
所以模板编程有时候你要考虑一下参数的特殊性。这时候我们就要用到显示具体化了
其中template <>为关键字,如果编译器可以根据参数列表推断模板类型那么< Type>中的Type为可选项
示例:
上卖弄三种分别为非模板函数,模板的显式具体化,模板函数
如果程序中同时定义了三种函数,会优先调用非模板函数,然后模板的显式具体化,最后模板函数
在以前c++只能通过判断函数参数来实例化函数,这种叫做隐式实例化而现在的c++可以通过显式实例化了,格式如下
上面的代码告诉编译器创建一个接受Type类型函数的实例,其中template为关键字,必须要写的。
示例:
上面的实例化告诉编译器使用swap模板生成一个接受int参数的函数实例,他已经在代码中了。
而模板显式具体化,告诉编译器当调用函数时如果参数为int时,就按照模板具体化定义的形式创建函数。
除了上面的显示实例化的手段,我们还可以在程序中手动使用函数模板来创建显示实例化,如下
上卖弄的模板函数与swap(i,d)是不匹配的,因为两个参数是不同的,但是通过显式实例化swap(i,d)来用模板 swap(T a,T b)创建double版本的函数,然后int的值会自动转换为double,以便函数使用
如果调用
上面#3,#5,#6都是原型匹配,但是#3,#5优先于#6,#6优先于#1
所以c++11引入了关键字decltype来解决这个问题
上面是三种decltype的简单使用。而对于如下标准格式
decltype(expression) var;
编译器会编译一个核对表,核对表的简化版如下
第一步:如果expresssion是一个没有用括号的标识符,则var的类型与该标识符相同,包括const等修饰符
第二步:如果experssion是一个函数调用,var是的类型与函数返回值一样
Note:
这实际不会调用函数,编译器会根据函数原型判断返回值类型
第三步:如果expression是一个左值,则var为指向类型的引用。这好像意味着前面w应为引用类型,因为x是一个左值,但是这种情况下已经在第一步处理过了。要进入第三步expression不能是未用括号括起来的标识符
第四步:如果前面条件都不满足,则var的类型与expression类型相同
decltype (a+b) 不行吗?因为这时候还没有定义a,b,编译器不知道a,b是什么。c++11为auto新增了语法功能来解决这个问题,如下
auto告诉编译器返回类型在后面写着。他可以和decltype 连用
这样就完成了返回类型的自动换了。
定义和使用函数模板
格式如下:template<typename AnyType> returnType functionName(argument-list){ // do something }
其中template和typename是关键字。
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> 4000 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);
这样就完成了返回类型的自动换了。
相关文章推荐
- c++入门学习(函数模板)
- 王老师 C++ 函数重载和模板 第二讲
- C++箴言:用成员函数模板接受兼容类型
- C++中 函数,函数模板,函数对象,函数对象模板 与 回调机制 不得不说的事
- 利用C++模板,代替虚函数,实现类的静态多态性(加入性能测试部分)
- C++中的函数模板
- C/C++ 函数模板
- C++模板之函数模板
- 【转】王老师 C++ 函数重载和模板
- [C++再学习系列] 函数模板和类模板
- 未解决-深入C++之函数模板
- C++模板的定制一:定制函数模板
- C++模板的定制五:对定制成员函数的补充
- C++ 函数模板和类模板(转)
- C++模板:函数模板和模板函数
- 王老师 C++ 函数重载和模板 第一讲
- 利用C++模板,代替虚函数,实现类的静态多态性(加入性能测试部分)
- 利用C++模板,代替虚函数,实现类的静态多态性(加入性能测试部分)
- c++学习---函数模板
- C++ 函数模板 二义性 问题