函数模板

来源:互联网 发布:网络教育质量监管系统 编辑:程序博客网 时间:2024/06/06 11:03

1.定义:
函数模板提供了一种可以生成各种类型函数的机制。如果一个函数的实现对一组实例都是相同的,区别仅在于每个实例处理不同的数据类型,那么该函数就可以定义为函数模板。

2.函数模板的语法:
template<模板参数表> 函数返回类型 函数名 (函数参数表){函数体}

1.模板参数表:模板定义以关键字template开始,后跟一个模板参数列表,这是一个逗号分隔的一个或多个模板参数的列表,用<和>包围起来。模板参数不能为空,可以是类型参数,它代表了一种类型;也可以是非类型参数,它代表了一个常量表达式。模板***类型参数***由关键字class或typename后加一个标识符构成。class和typename在模板参数表中的意义是一样的表示后面的标识符代表一个潜在的内置类型或用户自定义的类型。当模板被实例化时,会由实际的类型替换模板的类型参数模板***非类型参数***由一个普通的的参数声明构成。模板非类型参数表示该参数名代表了一个潜在的值,这个值是模板定义的中的一个常量。在模板实例化时,非类型参数会被一个编译时刻已知的常量值代替。2.函数定义除了可以使用模板参数指定的类型或常量值以外,函数模板的定义与普通函数的定义相同。3.例子template <typename T> int compare(const T& v1,const T& v2){    if(v2 < v1) return 1;    if(v1 < v2) return -1;    return 0;}

3.函数模板的实例化
函数模板根据一组实际类型或值构造出独立的函数,这个构造过程被称为模板实例化。
例如:
compare(5,7); //T为int,实例化得到 int compare(const int&,const int&)

vector v1{1,2,3},v2{2,3,4};
compare(v1,v2); //T为vector,实例化得到 int compare(const vector &,const vector &)

编译器生成的这些版本被称为 模板的实例
在使用函数模板时,必须能通过上下文为每一个模板实参确定唯一一个的类型或值,否则编译出错。
例如:
compare(2 ,5.7);//错误:推演const T的类型出现冲突:int 和 double
解决办法:
显示指定模板实参
当模板实参被显示指定时,函数参数的类型已经确定,不必推演模板实参。函数实参可以进行隐式类型转换.例如:
compare(2 ,5.7); //正确,显示指定,对实参2进行类型转换
compare(2 ,5.7); //正确,显示指定,对实参5.7进行类型转换
也可以显示地指定一部分模板实参,其余(尾部)的实参由编译器从函数的实参中推演得到。例如:

template<class T1, class T2, class T3> T1 func(T2 arg1,T3 arg2) { /*...*/  }int main() {    int x, y;    double d;    x  = func(y, d);                  //错误:调用中没有T1的信息,不能推演出模板实参T1    x = func<int, int, double>(y, d); //正确,显示指定    x = func<int>(y, d);              //正确,显示指定了T1,能够推演出T2,T3}

4.模板编译
当编译器遇到一个模板定义时并不生成代码。只有当实例化时才生成代码。这一特性影响了我们如何组织代码以及错误何时被检测到。与普通函数不同,在调用一个函数模板生成一个实例时,编译器需要知道函数模板的定义,而不只是声明。因此,模板的头文件通常既包含模板的声明,也包含模板的定义。
在编写模板时,代码是不能针对某种特定类型的,但模板代码通常对其所使用的类型有一些假设。例如:
Salea_data data1,data2; //假设 Sales_data 是已实现的类,但未定义运算符 <
compare(data1, data2);
此调用实例化了compare的一个版本,将T替换为Sales_data 并未定义此运算符< 。则该实例编译无法通过,这样的错误直至编译器在类型 Sales_data上实例化compare时才会被发现。

原创粉丝点击