函数模板提供了一种函数行为,该函数行为可以用多种不同的类型进行调用,也就是说,函数模板代表一个函数家族,这些函数的元素是未定的,在使用的时候被参数化。

本文地址:http://www.cnblogs.com/archimedes/p/cpp-template.html,转载请注明源地址。

下面举一个简单的例子:

定义模板:

  1. template<typename T>
  2. inline T const& max(T const& a, T const& b)
  3. {
  4. return a < b ? b : a;
  5. }

这个模板定义指定了一个“返回两个值中最大者”的函数家族,这两个值通过函数参数a , b传递给函数模板的,而参数的类型还没有确定,用模板参数T来代替。
其中,typename可以用class来代替,但是建议使用typename

完整代码如下:

  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4.  
  5. template<typename T>
  6. inline T const& max(T const& a, T const& b)
  7. {
  8. return a < b ? b : a;
  9. }
  10.  
  11. int main()
  12. {
  13. int i = ;
  14. cout<<"max(7, i): "<<::max(, i)<<endl;
  15.  
  16. double f1 = 3.4;
  17. double f2 = 5.6;
  18. cout<<"max(f1, f2): "<<::max(f1, f2)<<endl;
  19.  
  20. string s1 = "mathematics";
  21. string s2 = "math";
  22. cout<<"max(s1, s2): "<<::max(s1, s2)<<endl;
  23. cin.get();
  24. return ;
  25. }

实参的选择:

模板参数可以根据我们传递的实参来决定,如果我们传递了两个int给参数类型T const&,那么C++编译器得出结论:每个T都必须正确的匹配,如果此时传递的实参为:max(4, 4.2),则出现编译错误

有3种方法来处理上面的错误:

1、对实参进行强制类型转换,使它们可以互相匹配:

max(static_cast<double>(4), 4.2);

2、显示指定(或限定)T的类型:

max<double>(4, 4.2)

3、指定两个参数可以具有不同的类型

模板参数

函数模板有2种类型的参数:

1、模板参数:位于函数模板名称的前面,在一对尖括号内部进行声明:

template<typename T>

2、用参数:位于函数模板名称之后,在一对圆括号内部进行声明:

...max(T const& a, T const& b)

可以声明任意数量的模板参数,在函数模板的内部,不能指定缺省的参数。

  1. template<typename T1, typename T2>
  2. inline T1 max(T1 const& a, T2 const& b)
  3. {
  4. return a < b ? b : a;
  5. }
  6. ...
  7. max(, 4.2);

可以引入第三个模板实参类型,来定义函数模板的返回类型:

  1. template<typename T1, typename T2, typename RT>
  2. inline RT max(T1 const& a, T2 const& b);
  3. ...
  4. max<int, double, double>(, 4.2);

行得通,但是很麻烦

还有一种方法是只显示的指定第一个实参,而让演绎过程推导出其余的实参。

  1. template<typename RT, typename T1, typename T2>
  2. inline RT max(T1 const& a, T2 const& b);
  3. ...
  4. max<double>(, 4.2); //ok, 返回类型是double

重载函数模板

和普通函数一样,函数模板也可以被重载,示例代码如下:

  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4.  
  5. inline int const& max(int const& a, int const& b)
  6. {
  7. return a < b ? b : a;
  8. }
  9.  
  10. template<typename T>
  11. inline T const& max(T const& a, T const& b)
  12. {
  13. return a < b ? b : a;
  14. }
  15.  
  16. template<typename T>
  17. inline T const& max(T const& a, T const& b, T const& c)
  18. {
  19. return ::max(::max(a, b), c);
  20. }
  21.  
  22. int main()
  23. {
  24. cout<<::max(, , )<<endl; //调用具有3个函数的模板
  25. cout<<::max(7.9, 34.5)<<endl; //调用max<double>(通过实参演绎)
  26. cout<<::max('a', 'y')<<endl; //调用max<char>(通过实参演绎)
  27. cout<<::max(, )<<endl; //调用int重载的非模板函数
  28. cout<<::max<>(, )<<endl; //调用max<int>(通过实参演绎)
  29. cout<<::max<double>(, )<<endl; //调用max<double>(没有实参演绎)
  30. cout<<::max('a', 23.4)<<endl; //调用int重载的非模板函数
  31.  
  32. cin.get();
  33. return ;
  34. }

下面的更有用的例子将会为指针和普通的C字符串重载这个求最大值的模板:

  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4.  
  5. //求两个任意类型值的最大者
  6. template<typename T>
  7. inline T const& max(T const& a, T const& b)
  8. {
  9. return a < b ? b : a;
  10. }
  11.  
  12. //求两个指针所指向值的最大者
  13. template<typename T>
  14. inline T* const& max(T* const& a, T* const& b)
  15. {
  16. return a < b ? b : a;
  17. }
  18.  
  19. //求两个C字符串的最大者
  20. inline char const* const& max(char const* const& a, char const* const& b)
  21. {
  22. return *a < *b ? b : a;
  23. }
  24.  
  25. int main()
  26. {
  27. int a, b;
  28. a = ;
  29. b = ;
  30. ::max(a, b); //max()求两个int值的最大值
  31.  
  32. string s = "hey";
  33. string t = "you";
  34. cout<<::max(s, t)<<endl; //max()求两个string类型的最大值
  35.  
  36. int* p1 = &b;
  37. int* p2 = &a;
  38. cout<<::max(p1, p2)<<endl; //max()求两个指针所指向值的最大值
  39.  
  40. char const* s1 = "Davide";
  41. char const* s2 = "Nico";
  42. cout<<::max(s1, s2)<<endl; //max()求两个c字符串的最大值
  43.  
  44. cin.get();
  45. return ;
  46. }

以上在所有实现重载里面,都是通过引用来传递每个实例的,但是一般而言,在重载函数模板的时候,最好只是改变那些需要改变的内容,应该把改变限制在以下两个方面:

改变参数的数目或显式地指定模板参数

对于以上的重载,如果改为基于C-string的max()函数,通过传值来传递参数,就不能实现3个参数的max()版本:

  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4.  
  5. //求两个任意类型值的最大者(通过传引用进行调用)
  6. template<typename T>
  7. inline T const& max(T const& a, T const& b)
  8. {
  9. return a < b ? b : a;
  10. }
  11.  
  12. //求两个C字符串的最大者(通过传值进行调用)
  13. inline char const* max(char const* a, char const* b)
  14. {
  15. return strcmp(a, b) < ? b : a;
  16. }
  17.  
  18. //求3个任意类型值的最大者(通过传引用进行调用)
  19. template<typename T>
  20. inline T const& max(T const& a, T const& b, T const& c)
  21. {
  22. return max(max(a, b), c);
  23. }
  24.  
  25. int main()
  26. {
  27. cout<<::max(, , )<<endl; //ok
  28.  
  29. const char* s1 = "frederic";
  30. const char* s2 = "anica";
  31. const char* s3 = "lucas";
  32. cout<<::max(s1, s2, s3)<<endl; //error
  33.  
  34. cin.get();
  35. return ;
  36. }

错误在于:如果对3个C-string调用max,则语句return max(max(a, b), c);将产生错误

原因是对于C-string而言,max(a, b)产生了一个新的临时局部值,该值有可能被外面的max函数以传引用的方式返回,将导致传回无效的引用。

C++函数模板的更多相关文章

  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. JS文件放在头还是尾

    目前绝大部分的浏览器都是采取阻塞方式(Scripts Block Downloads)加载Javascript文件的:javascript在头部会阻止其他元素并行加载(css,图片,网页):这种机制的 ...

  2. 哇塞,原来自己写 Google Chrome 浏览器扩展(插件)这么容易!

    1. 首先新建一个记事本,命名为 manifest.json,这是写 Google Chrome 浏览器扩展必须的文件 { "manifest_version": 2, " ...

  3. actionbar部分设置:colorPrimary colorPrimaryDark colorAccent 下部阴影

    去除actionbar下阴影: <item name="android:windowContentOverlay">@null</item>

  4. 修改oracle重做日志文件大小

    创建3个新的日志组 SQL> ALTER DATABASE ADD LOGFILE GROUP 4 ('/u01/app/oracle/oradata/orcl/redo06.log') SIZ ...

  5. 浅谈java类集框架和数据结构(1)

    在另外一篇博客我简单介绍了java类集框架相关代码和理论. 这一篇博客我主要分析一下各个类集框架的原理以及源码分析. 一:先谈谈LinkedList 这是LinkedList源码的开头,我们能看到几点 ...

  6. c# 编程语言 编译器 Roslyn

    4 月3日,微软向公众发布了Roslyn编译器项目,该项目采用了Apache开源许可协议.C#的创始人 Anders Hejlsberg在Build大会的第二场主题演讲中将这一令人震惊的消息公之于众. ...

  7. 重构13天 抽取方法对象(Extract Method Object)

    理解:本文中的“提取方法对象”是指当你发现一个方法中存在过多的局部变量时,你可以通过使用“提取方法对象”重构来引入一些方法,每个方法完成任务的一个步骤,这样可以使得程序变得更具有可读性. 详解:如下代 ...

  8. Asp.Net 三层架构之泛型应用

    一说到三层架构,我想大家都了解,这里就简单说下,Asp.Net三层架构一般包含:UI层.DAL层.BLL层,其中每层由Model实体类来传递,所以Model也算是三层架构之一了,例外为了数据库的迁移或 ...

  9. .net 读书笔记

    好书不能只读一遍,这两天又翻看了一遍<你必须知道的.NET>,重温了下基础,重温了下经典,简单记录了下来. 内存分配:CLR 管理内存的区域,主要有三块,分别为: 线程的堆栈,用于分配值类 ...

  10. c#使用aspose.cells 从datatable导出数据到excel

    string json=value.Value; DataTable dt=Utils.JsonDataTableConvert.ToDataTable(json); string fileName ...