稍微深入函数模板
发布日期:2022-02-07 06:39:45 浏览次数:6 分类:技术文章

本文共 3504 字,大约阅读时间需要 11 分钟。

C++中的函数新特性(二)

  1. 浅谈函数模板和泛型编程
  2. 函数模板的实现原理
  3. 扩展:模板重载简介
  4. 局限性:模板的具体化
  5. 局限性:模板实例的选择
  6. 函数的选择
  7. 局限性:类型的判定

函数模板

浅谈函数模板与泛型编程

泛型编程

通过一种语言机制
实现一个通用的方法(标准容器库)
通用是指:每一种数据类型都能用

函数模板怎么实现泛型编程呢?

上次的例子:

如果我要打一个交换两个int变量的函数
我可以这样

void swap(int & a, int & b){    int temp;    temp = a;    a = b;    b = temp;}

如果通过函数模板来实现泛型编程

则可以这样

template 
void swap(T & a, T & b){ T temp; temp = a; a = b; b = temp;}

关键字:template(模板)

关键字:typename

第一行,指出这是一个函数模板

一个可替代的变量类型,我们暂且命名为T
然后后面函数的定义
就用T来代替具体的类型
之后我们的函数调用
就可以用这一个swap函数,去交换int变量
去交换double变量

实际上函数模板就是在编译的时候

将T换成所需要的类型
就像 typedef T int ;一样

所以我们在调用这个函数的时候

可以这样调用

double a,b;swap(a,b);int c,d;swap(c,d);

然后就达到了泛型编程的目的

对,无论什么类型,都可以调用
吗?
当然,事情并没有那么简单。
数据类型,远远不止这几种基本类型
还有结构体,还有类
还有……………………
这个在后面的局限性里拓展一下

函数模板的实现原理

template 
void swap(T & a, T & b){ T temp; temp = a; a = b; b = temp;}

函数模板的语法

template是模板的关键字
typename是在模板中说明类型的关键字
template < typename T >
在第一行中,先声明了一个类型参数T
然后在函数的具体定义中,
把需要用到该类型的全部用T

原理:

在编译过程
编译器会自动根据函数的调用情况
知道需要使用哪种类型的函数
然后就会
直接把T替换成对应的类型
生成一个新函数

所以,在编译过程,

模板就会变成真正的函数
(这个过程叫做模板的实例化)
在编译过后,程序就没有模板了
只有对应的函数

模板的重载

同函数一样,模板也是可以重载的

(还记得什么叫函数的重载吗?)
(C++中允许同名函数的存在)
(虽然同名,不过会根据函数的特征标选择)
(所以不会产生冲突)

模板重载

同名函数模板
在C++中是允许存在的
前提是模板的参数不同

先放个例子

template 
T add(T a, T b){ return a+b;}

对这个模板,

我们可以使两个相同类型的变量相加
然后返回他们的和

template 
T1 add(T1 a, T2 b){ return a+b;}

对这个模板

我们可以使两个具有不同类型的变量相加
并且返回第一个变量所具有的类型
当然,我们还可以这样

template 
T add(T a, T b){ return a+b+t;}

而这个模板,我们可以在模板参数里

放入一个int类型的整数
然后相加的时候加多一个数

模板局限性1:

如果模板对某一种类型不合适

可以自己另外定义一个函数代替模板吗

假设我现在有这样一个模板

template 
void swap(T & a, T & b){ T temp; temp = a; a = b; b = temp;}

然后我有这样一种

用结构体定义的数据类型

struct person{    char name[40];    int age;};

我能否这样?

person p1,p2;// after initializationswap( p1, p2 );

虽然C++允许结构体的赋值

可是,如果我只想交换age这一个变量呢
只想交换年龄而不改名可以吗?

模板的显式具体化技术

我们想做的事情就是

想让一个模板,对其余的所有类型都适用
唯独用person类型的时候
我想另外定义一个而不使用模板的定义
这里,我们使用模板的显式具体化技术

具体化:

就是对某一种类型给出具体的定义

这里我先给出person类型的显式具体化例子

//函数原型template <> void swap
(person & a, person & b);//函数定义template <> void swap
(person & a, person & b){ int temp; temp = a.age; a.age = b.age; b.age = temp;}

对比普通模板

//函数原型template 
void swap(T & a, T & b);//函数定义template
void swap(T & a, T & b){ T temp; temp = a; a = b; b = temp;}

区别1:template还在

但是后面的<>中可自定义的类型参数没有了
也就是说没有了可自定义的类型参数
区别2:函数名
函数名后面加上了< person >
表明这是该模板下该类型的定义
区别3:形参列表及函数定义
没有了自定义的类型参数
后面的一切操作
都是由具体的类型完成

函数的具体化

使得在调用函数的时候
能够根据类型,选择使用模板函数
还是用模板函数下的具体化

模板局限性2:

假设有这样一种模板函数

template 
T add(T a, T b){ return a+b;}

问题描述

使这个模板函数这样调用

int   a = 2;double d = 3.0;add(a,d);

模板函数该如何选择类型?

这里我们需要用到模板的另一种语法

模板的实例化技术

什么是实例化?

就是从模板变成真正的函数

实例化分为
隐式实例化和显式实例化

隐式实例化

在前面的原理中我们说到

模板在编译过程就会变成真正的函数
在编译后
代码是没有模板这一种东东的
模板,已经变成了一个一个的函数
如果以上面的swap函数为例
我一旦调用swap函数

int a = 2;int b = 3;add(a,b);

编译器便会知道我需要int类型的add函数

然后就会帮我通过模板
生成int类型函数

int add(int  a, int  b){    return a+b;}

这样,就是函数模板的一个实例化

由于我并没有告诉编译器要实例化
只是编译器比较聪明知道应该要这么做
就叫隐式实例化

显式实例化

如果要明确的告诉编译器

需要实例化某一个类型的函数
我可以这样做

template void add
(int , int );

通过这一条语句

编译器便会知道需要生成int类型的swap函数
(无论我后面有没有调用)

还可以通过这样的方法

在函数调用的时候调用显式实例化的一个函数

int x = 3;double y = 3.2;double sum = add
(x,y);

从而解决模板函数调用模糊不清

不知道该调用谁的问题

提出几个问题

  1. 所有类型都可以直接相加吗?
    如:我用前面的add函数模板,去相加字符串可以吗?

其实是不可以的

但是如果可以自己为字符串重载运算符+
(也就是自己定义一个适用于字符串的+运算符)
也许就可以了

  1. 如果我在模板中不知道该返回什么类型的参数
template 
???? add(T1 a, T2 b){ return a+b;}

上面的程序,我可不能确定a+b的类型呀

可能是T1,也可能是T2
这可不能随便定下来呀
能不能在运行的时候根据我的参数的输入决定呢?

这个又能扯到很多东西……下次再说说

我还是希望能够快点讲到类……

这样又有一堆东西可以写了……

转载地址:https://blog.csdn.net/wyfwyf12321/article/details/54669487 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:C++中的函数新特性
下一篇:名称空间与作用域

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月18日 11时00分37秒