RELATEED CONSULTING
相关咨询
选择下列产品马上在线沟通
服务时间:9:30-18:00
你可能遇到了下面的问题
关闭右侧工具栏
深入C++之函数模板
  • 作者:zhaozj
  • 发表时间:2020-12-23 11:03
  • 来源:未知

深入C++之函数模板[原创] zengyi820 2003-07-01
第十章 函数模板 Chapter 10 Function template 本章要点概述: 1.什么是模板(what a function template is) 2.定义和使用模板(how to define and use a function template) 3.函数模板的推演过程(template argument deduction) 4.引用模板实例时如何指定显示模板参数(how explicit template arguments can be specified when referring to a function template instantiation) 5.编译器模板的初始化以及对程序组织的要求(how the compiler instantiates templates and the requirements this imposes on the organization of our programs) 6.定义函数模板实例的特化版本(how to define a specialization for a function template instantiation) 7.函数模板的重载及其解析过程如何工作(how function templates can be overloaded and how overload resolution involving function templates works) 8.函数模板定义中的名字解析(name resolution in function template definitions) 9.函数模板定义在名字空间中的方式(how function templates can be defined in namespaces) 10.1函数模板的定义(Function Template Definition) (1)由强类型语言需求引出的问题: 强类型语言需要我们对不同的类型参数定义不同类型的函数 int min( int a, int b ){ ?? return a < b ? a : b; }double min( double a, double b ) { return a < b ? a : b; } ??我们尝试用预处理器的宏扩展设施解决这个问题 #define min(a,b) ((a) < (b) ? (a) : (b)) 这样的工作机制存在问题:我们来解析一下,预处理器的宏扩展设施的工作机制不是对函数的调用,而是简单的提供参数的替换,两个参数值被计算了两次,一次是比较a,b。一次是宏的返回值计算。 ??使用函数模板保留了函数定义和函数调用的语义(函数调用之前实参只被计算一次),其核心算法的功能是:程序员可以对函数接口的全部或者部分类型进行参数化,而函数体保持不变。 (2)函数模板的构造准则(The Principle of Function Template Creation) 函数的实现在一组实例上保持不变,每个实例都处理一种唯一的数据类型,这样的函数就可以构造成函数模板 template Type min( Type a, Type b ) { return a < b ? a : b; } int main() { // ok: int min( int, int ); min( 10, 20 ); // ok: double min( double, double ); min( 10.0, 20.0 ); return 0; } (3)函数模板的定义(Function Template Definition) template总是放在模板定义与声明的最前面 <>中的是模板参数表,不可为空,模板参数有两类: 模板类型参数(template type parameter list):由关键字class或typename(在函数模板的参数表中两者意义相同)后加一个标识符构成。标识符(如上面的Type)可以是任何名字。 模板实例化时,实际的内置或用户定义类型将替换模板的类型参数。模板类型参数用来声明变量和强制类型转换。有效的模板实参类型:int、double、char*、vector 或list * 模板非类型参数(template nontype parameter):由一个普通的参数声明构成,代表了一个潜在的值,该值是模板定义中的一个常量 template Type min( Type (&arr) [size] ); Size就是该函数模板的非类型参数,代表arr指向的数祖的长度,函数min()实例化时,size将被编译时已知的常量值替代。模板非类型参数常用在数组声明中指定数组的大小或者是作为枚举常量的初始值 调用函数和取函数地址是函数的两种使用方法 (4)函数模板定义中应注意的若干问题 a.如果在全局域中声明了与模板参数同名的对象、函数或类型,则该全局名将被隐藏,如下程序段: typedef double Type; template Type min( Type a, Type b ) { Type tmp = a < b ? a : b; // tmp 类型为模板参数 Type,而不是全局的typedef return tmp; } b.在函数模板定义中声明的对象或类型不能与模板参数同名 template Type min( Type a, Type b ){ typedef double Type; // 这里就重新声明了模板参数,所以是个错误 Type tmp = a < b ? a : b; return tmp; } c.模板类型参数名可以被用来指定函数模板的返回值 template T1 min( T2, T3 ); T1指明了函数min()返回值的类型,T2和T3指明的是参数的类型 d.模板参数名在同一模板中不可重名,但是在不同的函数模板声明中就可以重复的使用。 e.每个模板类型参数都必须有关键字typename或者class在前面,两者可以互换。 f.模板函数被声明为inline或extern的格式:指示符要放在参数表的后面 正确: template inline Type min( Type, Type ); 错误: inline template Type min( Array , int ); 下面我们来看经典教材C++ Primer当中的两个练习以加深巩固. 指出下列函数模板的定义哪些是错误的,哪些是这确的,并将其改正 (a) template void foo( T, U, V ); 模板的定义应该为template ,依据:每个模板类型参数都必须有关键字typename或者class在前面,两者可以互换。 (b) template T foo( int *T ); 正确 (c) template T1 foo( T2, T3 ); 正确 (d) inline template T foo( T, unsigned int* ); 应该为: template inline T foo( T, unsigned int* ); 指示符:模板函数被声明为inline或extern的格式时指示符要放在参数表的后面 (e) template void foo( myT, myT ); 模板参数名在同一模板中不可重名。 可以改为: template void foo( myT, myT ); (f) template foo( T, T ); 正确 (g) typedef char Ctype; template Ctype foo( Ctype a, Ctype b ); 正确 练习10.2 下列模板重复声明中哪些是错误的,为什么 (a) template Type bar( Type, Type ); template Type bar( Type, Type ); (b) template void bar( T1, T2 ); template void bar( C1, C2 ); 两个都是正确的