工控课堂

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

工控课堂 首页 工控文库 工控上位机 查看内容

C++函数模板详解,手把手教你!

2018-12-25 20:18| 发布者: gk-auto| 查看: 47| 评论: 24|原作者: gk-auto

摘要: 经常有碰到函数模块的应用,很多书上也只是略有小讲一下,今天又狂碰到函数模块,无奈特地找来C++编程经典翻阅一遍,终于有所全面了解.....++ C++函数模块基础:一. 问题:强类型语言要求我们为所有希望比较的类型都实现 ...
经常有碰到函数模块的应用,很多书上也只是略有小讲一下,今天又狂碰到函数模块,无奈特地找来C++编程经典<>翻阅一遍,终于有所全面了解.....++>

C++函数模块基础:
一. 问题:
强类型语言要求我们为所有希望比较的类型都实现一个实例
int min( int a, int b ) {
return a < b ? a : b;
}
double min( double a, double b ) {
return a < b ? a : b;
}

有一种方法可替代为每个min()实例都显式定义一个函数的方法这种方法很有吸引力但是也很危险.那就是用预处理器的宏扩展设施例如  :
#define min(a,b) ((a) < (b) ? (a) : (b))
在复杂调用的情况下,它的行为是不可预期的,这是因为它的两个参数值都被计算两次. 一次是在a 和b 的测试中另一次是在宏的返回值被计算期间.

#include
#define min(a,b) ((a) < (b) ? (a) : (b))
const int size = 10;
int ia[size];
int main() {
int elem_cnt = 0;
int *p = &ia[0];
// 计数数组元素的个数
while ( min(p++,&ia[size]) != &ia[size] )
++elem_cnt;
cout << "elem_cnt : " << elem_cnt
<< "\texpecting: " << size << endl;
return 0;
}      
执行该程序的结果是下面不正确的计算结果:  elem_cnt : 5 expecting: 10
min()的宏扩展在这种情况下会失败因为应用在指针实参p 上的后置递增操作随每次扩展而被应用了两次


二 .解决办法:
函数模板提供了一种机制通过它我们可以保留函数定义和函数调用的语义在一个程序位置上封装了一段代码确保在函数调用之前实参只被计算一次.

函数模板提供一个种用来自动生成各种类型函数实例的算法程序员对于函数接口参数和返回类型中的全部或者部分类型进行参数化(parameterize)而函数体保持不变.

下面是min()的函数模板定义

template
Type min( Type a, Type b ) {
return a < b ? a : b;
}

三.  具体操作
关键字template 总是放在模板的定义与声明的最前面关键字后面是用逗号分隔的模板参数表(template parameter list)它用尖括号<> 一个小于号和一个大于号括起来该列表是模板参数表不能为空模板参数可以是一个模板类型参数(template typeparameter)它代表了一种类型也可以是一个模板非类型参数(template nontype parameter)它代表了一个常量表达式模板类型参数由关键字class 或typename 后加一个标识符构成在函数的模板参数表中这两个关键字的意义相同。

模板非类型参数由一个普通的参数声明构成模板非类型参数表示该参数名代表了一个潜在的值而该值代表了模板定义中的一个常量例如size 是一个模板非类型参数它代表arr 指向的数组的长度
template
Type min( Type (&arr) [size] );

当函数模板min()被实例化时size 的值会被一个编译时刻已知的常量值代替。函数定义或声明跟在模板参数表后除了模板参数是类型指示符或常量值外函数模板的定义看起来与非模板函数的定义相同

template
Type min( const Type (&r_array)[size] )
{
/* 找到数组中元素最小值的参数化函数 */
Type min_val = r_array[0];
for ( int i = 1; i < size; ++i )
if ( r_array < min_val )
min_val = r_array;
return min_val;
}
在程序的运行过程中Type 会被各种内置类型和用户定义的类型所代替而size 会被各种常量值所取代这些常量值是由实际使用的min()决定的记住一个函数的两种用法是调用它和取它的地址

当一个名字被声明为模板参数之后它就可以被使用了一直到模板声明或定义结束为止模板类型参数被用作一个类型指示符可以出现在模板定义的余下部分它的使用方式与内置或用户定义的类型完全一样比如用来声明变量和强制类型转换模扳非类型参数被用作一个常量值可以出现在模板定义的余下部分它可以用在要求常量的地方或许是在数组声明中指定数组的大小或作为枚举常量的初始值




四.几点注意
①  如果在全局域中声明了与模板参数同名的对象函数或类型则该全局名将被隐藏在下面的例子中tmp 的类型不是double 是模板参数Type

typedef double Type;
template
Type min( Type a, Type b )
{
// tmp 类型为模板参数 Type
// 不是全局 typedef
Type tmp = a < b ? a : b;
return tmp;
}

②  在函数模板定义中声明的对象或类型不能与模板参数同名
template
Type min( Type a, Type b )
{
// 错误: 重新声明模板参数 Type
typedef double Type;
Type tmp = a < b ? a : b;
return tmp;
}

③  模板类型参数名可以被用来指定函数模板的返回位
// ok: T1 表示 min() 的返回类型
// T2 和 T3 表示参数类型
template
T1 min( T2, T3 );

④  模板参数名在同一模板参数表中只能被使用一次,但是模板参数名可以在多个函数模板声明或定义之间被重复使用
// 错误: 模板参数名 Type 的非法重复使用
template
Type min( Type, Type );

// ok: 名字 Type 在不同模板之间重复使用
template
Type min( Type, Type );
template
Type max( Type, Type );

⑤  如果一个函数模板有一个以上的模板类型参数则每个模板类型参数前面都必须有关键字class 或typename
// ok: 关键字 typename 和 class 可以混用
template
T minus( T*, U );
// 错误: 必须是 或
template
T sum( T*, U );

⑥ 为了分析模板定义编译器必须能够区分出是类型以及不是类型的表达式对于编译器来说它并不总是能够区分出模板定义中的哪些表达式是类型例如如果编译器在模板定义中遇到表达式Parm::name 且Parm 这个模板类型参数代表了一个类那么name 引用的是Parm 的一个类型成员吗.
template
Parm minus( Parm* array, U value )
{
Parm::name * p; // 这是一个指针声明还是乘法乘法
}
编译器不知道name 是否为一个类型因为它只有在模板被实例化之后才能找到Parm 表示的类的定义为了让编译器能够分析模板定义用户必须指示编译器哪些表达式是类型表达式告诉编译器一个表达式是类型表达式的机制是在表达式前加上关键字typename 例如如果我们想让函数模板minus()的表达式Parm::name 是个类型名因而使整个表达式是一个指针声明我们应如下修改
template
Parm minus( Parm* array, U value )
{
typename Parm::name * p; // ok: 指针声明
}
关键字typename 也可以被用在模板参数表中以指示一个模板参数是一个类型

⑦ 如同非模板函数一样函数模板也可以被声明为inline 或extern 应该把指示符放在模板参数表后面而不是在关键字template 前面
// ok: 关键字跟在模板参数表之后
template
inline
Type min( Type, Type );


timg.jpg

路过

雷人

握手

鲜花

鸡蛋

相关阅读

发表评论

最新评论

gdhzyd 2018-12-25 20:27
我顶,我顶,我顶顶顶
tthu007 2018-12-25 20:30
我顶,我顶,我顶顶顶
雪山飞狐 2018-12-25 20:44
我只是路过打酱油的。
雪山飞狐 2018-12-25 20:47
真是被感动的痛哭流涕……
gkket 2018-12-25 20:58
无私奉献,好工控人,32个赞送给你!!
虎山 2018-12-25 21:10
好东西一定要看看!
gxs1916 2018-12-25 21:11
无回帖,不论坛,这才是人道。
dp19980902 2018-12-25 21:14
太生气了,无法HOLD啦 >_<......
xuxing902 2018-12-25 21:15
我只是路过打酱油的。
赖宜谷 2018-12-25 21:47
绝对干货,楼主给力,支持了!!!
鸟托邦 2018-12-25 21:59
好东西一定要看看!
wosdao 2018-12-25 22:03
大家都不容易!
啊哈肆 2018-12-25 22:09
大家都不容易!
@Xizi_4RuJHeHx 2018-12-25 22:22
看了楼主的帖子,不由得精神一振,豁然开朗,牛掰
ssegg 2018-12-25 22:23
看到这帖子真是高兴!
陈记顺和 2018-12-25 22:23
好东西一定要看看!
风相随07 2018-12-25 22:24
淡定,淡定,淡定……
凉风 2018-12-25 22:26
谢谢您的分享!
李红 2018-12-25 22:29
加油,加油,不要沉下去,我是最热贴

查看全部评论(24)

QQ|免责声明|本站介绍|工控课堂 ( 沪ICP备14007696号-3 )|网站地图

GMT+8, 2019-3-21 23:26 , Processed in 0.033881 second(s), 30 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

返回顶部