原创博客:转载请标明出处:http://www.cnblogs.com/zxouxuewei/

模板从大体上,可以分为两种:函数模板和类模板。函数模板是算法库的基础,类模板是建立标准库容器和迭代器的基础。这一小节我们只介绍函数模板。

个人觉得,模板是C++对C的一个非常有力的扩充,即使我们不使用面向对象的机制,仅仅写面向过程的程序,它也是很有用的。因为它可以很大程度上避免了因为参数和函数返回值的类型不确定而引起的函数重载问题。

举一个例子,当我们要编写比大小的函数时,总会碰到这样的问题:函数形参的类型是不确定的:可以使两个int比较,也可以是int和double比 较等等。为了能调用各种类型的比较,唯一的办法就是编写大量的重载函数,让编译器自己判断具体使用哪个。但这样带来的问题很多:首先,必须要写大量的重载 函数;其次对于类型的匹配得非常小心,生怕出错;最后如果你想将大于变成小于,那么你的修改所有的重载函数。而有了模板之后,问题就变得简单多了。

[cpp] view plain copy

    template <typename T1,typename T2>
int compare(const T1 &v1,const T2 &v2)
{
if(v1 < v2)
return -;
else if(v2 > v1)
return ;
else
return ;

其中,模板以关键字template开头,后接模板形参列表,列表中可以有任意个模板类型形参。模板类型形参在整个模板的作用域中,就能当做某一类型使用 了。整个列表用尖括号括起来。每个模板类型形参前面都要使用class或者typename。二者没有什么本质的区别,typename是后来加入到 C++标准的,一些比较老的程序可能只是用class。后面的定义跟一般的函数类似,不再重复了。
然后我们就可以使用compare函数来比较任何支持“<”操作的类型(不论是内置的,还是自定义)了。

注意,我们不能直接:cout<<big("abc","def")<<endl;因为char[]类型不支持“<”操作,而string支持。

[cpp] view plain copy

    cout<<compare(,2.3)<<endl;
cout<<compare('a','x')<<endl;
string s1 = "abc";
string s2 = "def";
cout<<compare(s1,s2)<<endl;

下面说几点注意事项:

1.模板类型形参跟一般的形参类似,具有屏蔽外围变量类型的作用:例如:

那么在模板中,T表示的是模板类型,而不是double。

[cpp] view plain copy

    typedef double T;
template <typename T>
T foo(const T &val)
{
T tmp = val;
return tmp;
}

2.模板形参的名字不能在模板内部重用:

[cpp] view plain copy

    typedef double T;
template <typename T>
T foo(const T &a)
{
//typedef double T;
return a;
}

3.我们可以在模板内部定义自己的类型成员:

[cpp] view plain copy

    //使用迭代器打印容器元素
template <typename T>
void print_by_iter(T& c)
{
typename T::iterator iter = c.begin();
while(iter != c.end())
{
cout<<*iter++<<"\t";
}
}

这里面有两点要注意:首先,调用模板的实参类型必须有iterator。其次,最好在定义类型前加上typenme关键字告诉编译器,你指定的是一 个类型。在我们的例子中,不加的话也是能够顺利执行的,但对于有的情况,就必须加上了,比如:T::size_type  * p;

这句代码就有二义性了:如果size_type是一种类型,那么这里应该是声明了指向一个类型的指针的类型;如果它是一个对象,那么这里就是在做乘法运算。而编译器会默认的将它当做对象处理。

4.模板参数不必都是类型,我们也可以定义非类型模板形参。

[cpp] view plain copy

    //打印数组
template <typename T,size_t N>
void printValue(const T (&parm)[N])
{
for(std::size_t i = ;i != N ; i++)
cout<<parm[i]<<endl;
}

由于函数类型是数组的引用,所以传递给函数的,并不是数组的首地址,而是把数组的类型与元素的个数一起当做一种“类型”。其中非类型模板会被常量代替。当模板内部需要时,就能使用了。

最后是几条关于编写模板的建议:

1.模板的形参使用const引用。因为使用引用,可以避免那些不能复制的类型不能调用模板(比如流),而且如果调用模板的对象比较大,那么可以省去复制的代价。

[cpp] view plain copy

    //输出到流
template <typename T1,typename T2>
T1& print(T1& s,T2 val)
{
s<<val<<endl;
return s;
}

那么可以使用它向任意流中输出内容:

[cpp] view plain copy

    double dval = 0.88;
float fval = -12.3;
string oristr = "this is a test",desstr;
ostringstream oss(desstr);
ofstream outFile("result.dat"); print(cout,-);
print(cout,dval);
print(cout,oristr); print(outFile,-);
print(outFile,dval);
print(outFile,fval);
print(outFile,oristr); print(oss,-);
print(oss,dval);
print(oss,fval);
print(oss,oristr); cout<<oss.str()<<endl;
  而const则意味着你可以用常量调用这个函数:当没有const时:

[cpp] view plain copy

    template <typename T>
int big(T &a,T &b)
{
if (a>b)
return ;
if (a<b)
return ;
}

你只能使用:

[cpp] view plain copy

    int m = ;
int n = ;
cout<<big(m,n)<<endl;
  而如果加上const:int big(const T &a,const T &b)那么就可以: cout<<big(1,2)<<endl;

2.函数体中的测试只用<比较。因为有些类型不一定支持>操作:比如,在我们的比较函数中,使用的是 if(v1<v2)...if(v2<v1),而不是使用if(v1>v2)。其实,这是一种泛型编程的习惯。类似的习惯还有:可以用 “==”或者“!=”判断时,不用<一样。比如在for循环时,最好使用=!来当条件,而不是小于。

c++函数模板---3的更多相关文章

  1. c++函数模板作为类的成员函数,编译报错LNK2019的解决方法

    为了使某个类的成员函数能对不同的参数进行相同的处理,需要用到函数模板,即template<typename T> void Function(). 编译时报错LNK2019 解决方法: 1 ...

  2. C++STL - 函数模板

    模板主要是为了泛型编程,做到与类型无关 模板有函数模板和类模板,本文主要整理的是函数模板 1.函数模板定义 template<typename 类型形参1,typename 类型形参2,...& ...

  3. 使用getopt_long来解析参数的小函数模板

    getopt_long原型 #define no_argument 0 #define required_argument 1 #define optional_argument 2 struct o ...

  4. C++函数重载和函数模板

    1.函数重载 这是小菜鸟写的一个例子. 函数重载应该注意以下几点: 1.1重载函数有类似的功能: 1.2只能以参数的类型(形参个数和类型)来重载函数, int max(int a,int b);flo ...

  5. 零值初始化&字符串常数作为函数模板参数

    1.在定义一个局部变量时,并希望该局部变量的初始化一个值,可以显示调用其默认构造函数,使其值为0(bool类型默认值为false). template <typename T> void ...

  6. 让gcc支持成员函数模板的trick

    让gcc支持成员函数模板的trick 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循“署名-非商业用途-保持一致”创作公用协议   gcc 4.7.3 不支持成员 ...

  7. 不可或缺 Windows Native (16) - C++: 函数重载, 缺省参数, 内联函数, 函数模板

    [源码下载] 不可或缺 Windows Native (16) - C++: 函数重载, 缺省参数, 内联函数, 函数模板 作者:webabcd 介绍不可或缺 Windows Native 之 C++ ...

  8. Effective C++ -----条款45:运用成员函数模板接受所有兼容类型

    请使用member function templates(成员函数模板)生成”可接受所有兼容类型“的函数. 如果你声明member templates 用于“泛化copy构造”或“泛化assignme ...

  9. c++ 左值右值 函数模板

    1.先看一段代码,这就是一种函数模板的用法,但是红色的部分如果把a写成a++或者写成一个常量比如1,都是编译不过的,因为如果是a++的话,实际上首先是取得a的 值0,而0作为一个常量没有地址.写成1也 ...

  10. 读书笔记_Effective_C++_条款四十五:运用成员函数模板接受所有兼容类型

    比如有一个Base类和一个Derived类,像下面这样: class BaseClass {…}; class DerivedClass : public BaseClass {…}; 因为是父类与子 ...

随机推荐

  1. 第46套题【STL】【贪心】【递推】【BFS 图】

    已经有四套题没有写博客了.今天改的比较快,就有时间写.今天这套题是用的图片的形式,传上来不好看,就自己描述吧. 第一题:单词分类 题目大意:有n个单词(n<=10000),如果两个单词中每个字母 ...

  2. 查看UI调试界面利器 revealapp

    官网 http://revealapp.com 做iOS的开发,UI是非常非常重要的一环.调试时我们一般用模拟器,提交前用真机做测试.用模拟器来调试UI效果虽然快捷方便,但有时仍然希望有更强大的工具来 ...

  3. 集成支付宝钱包支付iOS SDK的方法与经验

    流程 摘自第一个文档<支付宝钱包支付接口开发包2.0标准版.pdf> 图中的“商户客户端”就是我们的iOS客户端需要做的事情: 调用支付宝支付接口 处理支付宝返回的支付结果 在调用支付宝支 ...

  4. 13个优秀的开源UML工具介绍

    本文将为您介绍12个优秀的UML工具: 1. StarUML StarUML(简称SU),是一种创建UML类图,是一种生成类图和其他类型的统一建模语言(UML)图表的工具.StarUML是一个开源项目 ...

  5. 记录一些容易忘记的属性 -- UILabel

    一:UILabel lbl.alpha=0.f;    lbl 透明,会影响子视图的显示 lbl.backgroundColor=[UIColor clearColor]; lbl 背景色透明,子视图 ...

  6. SharePoint开发 - 自定义导航菜单(二)母版页的菜单应用

    博客地址 http://blog.csdn.net/foxdave 接上篇点击打开链接 本篇叙述在母版页中应用之前的配置信息生成菜单,主要涉及到母版页的自定义,并应用了第三方控件库DevExpress ...

  7. 更改layout的布局

    创建了一个layout,缺省都是LinearLayout,原来都在xml把他改成其他布局,习惯了拖放的方式觉得挺麻烦. 其实vs2013有这个功能,就是在设计界面单机右键可以删除布局,然后拖一个布局进 ...

  8. php无缝连接滚动

    最近用到了,仿照别人的写了一个 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ht ...

  9. Chapter 5: Container

    Chapter 5: Container A container is a module that processes the requests for a servlet and populates ...

  10. 利用strut2标签自动生成form前端验证代码

    利用strut2标签自动生成form前端验证代码,使用到的技术有1.struts2标签,如<s:form> <s:textfieled>2.struts2读取*Validati ...