C++模版初探之函数模板(一)

来源:互联网 发布:java调用chrome内核 编辑:程序博客网 时间:2024/06/05 02:10

最近研究了下C++模板,对于C++模板有了一个初步认识,模板是C++一个很重要也是用途很广的一个属性,它很好的诠释了C++的重用属性。如下是我对模板的学习和总结:

C++模板主要分为:函数模板,类模版以及非类型模板。下面我将对这三种模板进行详细的介绍和说明。

废话少说,首先让我来看看函数模板究竟是个神马玩意。

一、定义

我们还是直接上一个简单代码,这样比较直观:

TestTemplate.h

template <typename T>

T const& Max(T const &a, T const &b)

{

return a < b ? b : a;

}

temlpate,typename是模板关键字,T(Type)代表模板类型参数(注意与非类型参数区别)。由于历史原因,typename关键字也可以由class代替,typename是C++后期才引进的,之前只能用class,目前class依然可用,但是class会给人带来一种误导T必须是class类型。所以我强烈推荐用typename.

二、使用

模板已经有了,那我们该如何使用模板呢?如下就是一个简单的调用:

#include <iostream>

#include <string>

#include "TestTemplate.h"

int main()

{

std::cout<<"Max(2,3):"<<Max(2,3)<<std::endl;

std::cout<<"Max(2.5,3.5):"<<Max(2.5,3.5)<<std::endl;


std::string str1 = "math";

std::string str2 = "chinese";

std::cout<<"Max(str1,str2):"<<Max(str1,str2)<<std::endl;

return 0;

}

从上面调用可以看出同一份代码我们可以用来处理不同类型的调用,这样大大节省了代码的书写,重用性很高。上面例子中我们用到了int,double,string三种不同的类型引数去调用函数,其实函数模板调用我们应该写为Max<int>(2,3)。同时这里引出了一个概念即以具体类型代替模板参数的过程称为实例化。

这里需要注意的一点是模板会被编译两次:

1.未实例化,只是对模板程序代码进行语法检查以发现诸如缺少分号等等语法错误。

2.实例化,编译器检查模板程序代码中所有调用是否合法会在这个阶段检查出来。

三、引数推导

上面我们稍微提了一下引数,我们这里再具体说说关于引数推导,当我们使用某一类型引数调用时,模板类型参数将以该引数类型确定下来。譬如:我们针对参数类型T const&处传两个int,编译器必然能够推导出T是int。注意这里并不允许类型自动转换即每个T都必须完全匹配气引数。例如:

Max(2,3) ; //OK

Max(2,3.5);//ERROR

有三种方式解决上述错误:

1.把两个引数转为相同类型:

Max(static_cast<double>2,3.5);

2.明确指定T的类型:

Max<double>(2,3.5);

3.明确指出使用不同模板类型:

template <typename T1, typename T2 >

T1 const& Max(T1 const &a, T2 const &b)

{

return a < b ? b : a;

}

我们仔细分析一下第三种解决方式,它确实存在不足之处。问题在于返回值的类型。如果你使用了其中一个类型,另一个类型可能被转化为该类型。C++没有提供一个用以选择一个值更大的类型。

由于调用参数的类型由模板参数建立,所以两者往往互相关联。我们把这种概念称为函数模板引数推导。对于引数推导原则我补充两句:由于模板参数和调用参数之间相互关联,如果编译器无法推导出模板参数,你必须在调用时明确指定模板参数。

四、函数模板重载

话不多说先上一个demo:

int const& Max(int const& a, int const& b)

{

return a < b ? b : a;

}

tempalete <typename T>

T const& Max(T const& a, T const& b)

{

return a < b ? b : a;

}

template <typename T>

T const& Max(T const& a, T const& b,T const& C)

{

return Max(Max(a, b), c);

}

int main()

{

Max(1,2,3);//唤起接收三个引数的函数

Max(1.2,3.2);//唤起max(double)(经由引数推导)

Max('A','B');//唤起max(char)(经由引数推导)

Max(1,2);//唤起接受两个int引数的非模版函数

Max<>(1,2);//唤起max(int)(经由引数推导)

Max<double>(1,2);//唤起max(double)(无需引数推导)

Max('a',1.2);//唤起接受两个int引数的非模版函数

}

这个例子说明:非模版函数可以和同名的函数模板共存,也可以和其相同类型的实例化函数共存。当其他要素都相等时,重载机制会优先选择非模版函数,而不是选择游函数模板实例化的函数实体。但是如果可由模板产生更佳匹配,则模板实例化会被编译器选中,上述第二和第三个说明这一点。

函数模板就先说到这里,如有不足或者不对地方请大家补充和指正。接下来将会继续说到类模板和非类型参数模板。

0 0
原创粉丝点击