C++函数模板
函数模板提供了一种函数行为,该函数行为可以用多种不同的类型进行调用,也就是说,函数模板代表一个函数家族,这些函数的元素是未定的,在使用的时候被参数化。
本文地址:http://www.cnblogs.com/archimedes/p/cpp-template.html,转载请注明源地址。
下面举一个简单的例子:
定义模板:
template<typename T>
inline T const& max(T const& a, T const& b)
{
return a < b ? b : a;
}
这个模板定义指定了一个“返回两个值中最大者”的函数家族,这两个值通过函数参数a , b传递给函数模板的,而参数的类型还没有确定,用模板参数T来代替。
其中,typename可以用class来代替,但是建议使用typename
完整代码如下:
#include<iostream>
#include<string>
using namespace std; template<typename T>
inline T const& max(T const& a, T const& b)
{
return a < b ? b : a;
} int main()
{
int i = ;
cout<<"max(7, i): "<<::max(, i)<<endl; double f1 = 3.4;
double f2 = 5.6;
cout<<"max(f1, f2): "<<::max(f1, f2)<<endl; string s1 = "mathematics";
string s2 = "math";
cout<<"max(s1, s2): "<<::max(s1, s2)<<endl;
cin.get();
return ;
}
实参的选择:
模板参数可以根据我们传递的实参来决定,如果我们传递了两个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)
可以声明任意数量的模板参数,在函数模板的内部,不能指定缺省的参数。
template<typename T1, typename T2>
inline T1 max(T1 const& a, T2 const& b)
{
return a < b ? b : a;
}
...
max(, 4.2);
可以引入第三个模板实参类型,来定义函数模板的返回类型:
template<typename T1, typename T2, typename RT>
inline RT max(T1 const& a, T2 const& b);
...
max<int, double, double>(, 4.2);
行得通,但是很麻烦
还有一种方法是只显示的指定第一个实参,而让演绎过程推导出其余的实参。
template<typename RT, typename T1, typename T2>
inline RT max(T1 const& a, T2 const& b);
...
max<double>(, 4.2); //ok, 返回类型是double
重载函数模板
和普通函数一样,函数模板也可以被重载,示例代码如下:
#include<iostream>
#include<string>
using namespace std; inline int const& max(int const& a, int const& b)
{
return a < b ? b : a;
} template<typename T>
inline T const& max(T const& a, T const& b)
{
return a < b ? b : a;
} template<typename T>
inline T const& max(T const& a, T const& b, T const& c)
{
return ::max(::max(a, b), c);
} int main()
{
cout<<::max(, , )<<endl; //调用具有3个函数的模板
cout<<::max(7.9, 34.5)<<endl; //调用max<double>(通过实参演绎)
cout<<::max('a', 'y')<<endl; //调用max<char>(通过实参演绎)
cout<<::max(, )<<endl; //调用int重载的非模板函数
cout<<::max<>(, )<<endl; //调用max<int>(通过实参演绎)
cout<<::max<double>(, )<<endl; //调用max<double>(没有实参演绎)
cout<<::max('a', 23.4)<<endl; //调用int重载的非模板函数 cin.get();
return ;
}
下面的更有用的例子将会为指针和普通的C字符串重载这个求最大值的模板:
#include<iostream>
#include<string>
using namespace std; //求两个任意类型值的最大者
template<typename T>
inline T const& max(T const& a, T const& b)
{
return a < b ? b : a;
} //求两个指针所指向值的最大者
template<typename T>
inline T* const& max(T* const& a, T* const& b)
{
return a < b ? b : a;
} //求两个C字符串的最大者
inline char const* const& max(char const* const& a, char const* const& b)
{
return *a < *b ? b : a;
} int main()
{
int a, b;
a = ;
b = ;
::max(a, b); //max()求两个int值的最大值 string s = "hey";
string t = "you";
cout<<::max(s, t)<<endl; //max()求两个string类型的最大值 int* p1 = &b;
int* p2 = &a;
cout<<::max(p1, p2)<<endl; //max()求两个指针所指向值的最大值 char const* s1 = "Davide";
char const* s2 = "Nico";
cout<<::max(s1, s2)<<endl; //max()求两个c字符串的最大值 cin.get();
return ;
}
以上在所有实现重载里面,都是通过引用来传递每个实例的,但是一般而言,在重载函数模板的时候,最好只是改变那些需要改变的内容,应该把改变限制在以下两个方面:
改变参数的数目或显式地指定模板参数
对于以上的重载,如果改为基于C-string的max()函数,通过传值来传递参数,就不能实现3个参数的max()版本:
#include<iostream>
#include<string>
using namespace std; //求两个任意类型值的最大者(通过传引用进行调用)
template<typename T>
inline T const& max(T const& a, T const& b)
{
return a < b ? b : a;
} //求两个C字符串的最大者(通过传值进行调用)
inline char const* max(char const* a, char const* b)
{
return strcmp(a, b) < ? b : a;
} //求3个任意类型值的最大者(通过传引用进行调用)
template<typename T>
inline T const& max(T const& a, T const& b, T const& c)
{
return max(max(a, b), c);
} int main()
{
cout<<::max(, , )<<endl; //ok const char* s1 = "frederic";
const char* s2 = "anica";
const char* s3 = "lucas";
cout<<::max(s1, s2, s3)<<endl; //error cin.get();
return ;
}
错误在于:如果对3个C-string调用max,则语句return max(max(a, b), c);将产生错误
原因是对于C-string而言,max(a, b)产生了一个新的临时局部值,该值有可能被外面的max函数以传引用的方式返回,将导致传回无效的引用。
C++函数模板的更多相关文章
- c++函数模板作为类的成员函数,编译报错LNK2019的解决方法
为了使某个类的成员函数能对不同的参数进行相同的处理,需要用到函数模板,即template<typename T> void Function(). 编译时报错LNK2019 解决方法: 1 ...
- C++STL - 函数模板
模板主要是为了泛型编程,做到与类型无关 模板有函数模板和类模板,本文主要整理的是函数模板 1.函数模板定义 template<typename 类型形参1,typename 类型形参2,...& ...
- 使用getopt_long来解析参数的小函数模板
getopt_long原型 #define no_argument 0 #define required_argument 1 #define optional_argument 2 struct o ...
- C++函数重载和函数模板
1.函数重载 这是小菜鸟写的一个例子. 函数重载应该注意以下几点: 1.1重载函数有类似的功能: 1.2只能以参数的类型(形参个数和类型)来重载函数, int max(int a,int b);flo ...
- 零值初始化&字符串常数作为函数模板参数
1.在定义一个局部变量时,并希望该局部变量的初始化一个值,可以显示调用其默认构造函数,使其值为0(bool类型默认值为false). template <typename T> void ...
- 让gcc支持成员函数模板的trick
让gcc支持成员函数模板的trick 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循“署名-非商业用途-保持一致”创作公用协议 gcc 4.7.3 不支持成员 ...
- 不可或缺 Windows Native (16) - C++: 函数重载, 缺省参数, 内联函数, 函数模板
[源码下载] 不可或缺 Windows Native (16) - C++: 函数重载, 缺省参数, 内联函数, 函数模板 作者:webabcd 介绍不可或缺 Windows Native 之 C++ ...
- Effective C++ -----条款45:运用成员函数模板接受所有兼容类型
请使用member function templates(成员函数模板)生成”可接受所有兼容类型“的函数. 如果你声明member templates 用于“泛化copy构造”或“泛化assignme ...
- c++ 左值右值 函数模板
1.先看一段代码,这就是一种函数模板的用法,但是红色的部分如果把a写成a++或者写成一个常量比如1,都是编译不过的,因为如果是a++的话,实际上首先是取得a的 值0,而0作为一个常量没有地址.写成1也 ...
- 读书笔记_Effective_C++_条款四十五:运用成员函数模板接受所有兼容类型
比如有一个Base类和一个Derived类,像下面这样: class BaseClass {…}; class DerivedClass : public BaseClass {…}; 因为是父类与子 ...
随机推荐
- dSYM atos crash log 定位到代码行的方法(转)
做iOS开发的时候,常常会遇到crash,需要分析call stack的时候.有时候App在别人的设备崩溃,把crash report在自己的机器上打开,Xcode没有自动的进行符号化.这时候就需要自 ...
- linux rdate
检查服务器时间,发现服务器时间与当前时间错了很多.于是调整. 使用ntpdate ,不管如何设置,包括关闭防火期,设置ntp.conf,结果都不成功. 随即使用网上提供的另外一种方法,临时先解决一下燃 ...
- shell 和awk性能对比
time for ((i=0;i<10000;i++)) do ((sum+=i)); done real 0m0.086suser 0m0.079ssys 0m0.007s ...
- java中DatagramSocket连续发送多个数据报包时产生丢包现象解决方案
try { //向指定的ip和端口发送数据~! //先说明一下数据是谁发送过来的! byte[] ip = InetAddress.getLocalHost().getHostAddress().ge ...
- ShortcutMapper – 热门应用程序的可视化快捷键
ShortcutMapper 是一个流行应用程序的键盘快捷键映射.该应用程序使用 Ajax 调用来加载键盘和应用程序数据.首先,试图找到一个在线资源,其中列出了每个平台的所有应用程序快捷方式.然后你可 ...
- Fast Image Cache – iOS 应用程序高性能图片缓存
Fast Image Cache 是一种在 iOS 应用程序中高效.持续.超快速的存储和检索图像的解决方案.任何良好的 iOS 应用程序的用户体验都应该是快速,平滑滚动的,Fast Image Cac ...
- iOS-UIScrollView-图片缩放
一. 实现功能 两个手指捏合,可以放大或者缩小图片. 二.原理说明 1. 实现缩放功能的四个步骤 (1) 让控制器遵守代理协议 (2) 让scrollView设置代理 self (3) 调用代理方法, ...
- The Linux Process Principle,NameSpace, PID、TID、PGID、PPID、SID、TID、TTY
目录 . 引言 . Linux进程 . Linux命名空间 . Linux进程的相关标识 . 进程标识编程示例 . 进程标志在Linux内核中的存储和表现形式 . 后记 0. 引言 在进行Linux主 ...
- sublime 插件zen coding
sublime的插件Zen Coding是一个编写html的神器,现在已经更名为Emmet了. 在sublime中的package需要搜索的是Emmet 相关网站: 官网 Zen Coding: 一种 ...
- 移动端手势库Hammer.js学习
感觉移动端原生支持的 touch.tap.swipe 几个事件好像还不够用,某些时候还会用到诸如缩放.长按等其他功能. 近日学习了一个手势库 Hammer.js,它是一个轻量级的触屏设备手势库,能识别 ...