[c++][语言语法]函数模板和模板函数 及参数类型的运行时判断
参考:http://blog.csdn.net/beyondhaven/article/details/4204345
参考:http://blog.csdn.net/joeblackzqq/article/details/7460704
1.函数模板的声明和模板函数的生成
1.1函数模板的声明
函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计。它的最大特点是把函数使用的数据类型作为参数。
函数模板的声明形式为:
template<typename 数据类型参数标识符>
<返回类型><函数名>(参数表)
{
函数体
}
其中,template是定义模板函数的关键字;template后面的尖括号不能省略;typename(或class)是声明数据类型参数标识符的关键字,用以说明它后面的标识符是数据类型标识符。这样,在以后定义的这个函数中,凡希望根据实参数据类型来确定数据类型的变量,都可以用数据类型参数标识符来说明,从而使这个变量可以适应不同的数据类型。例如:
template<typename T>
T fuc(T x, int y)
{
T x;
//……
}
如果主调函数中有以下语句:
double d;
int a;
fuc(d,a);
则系统将用实参d的数据类型double去代替函数模板中的T生成函数:
double fuc(double x,int y)
{
double x;
//……
}
函数模板只是声明了一个函数的描述即模板,不是一个可以直接执行的函数,只有根据实际情况用实参的数据类型代替类型参数标识符之后,才能产生真正的函数。
关键字typename也可以使用关键字class,这时数据类型参数标识符就可以使用所有的C++数据类型。
1.2.模板函数的生成
函数模板的数据类型参数标识符实际上是一个类型形参,在使用函数模板时,要将这个形参实例化为确定的数据类型。将类型形参实例化的参数称为模板实参,用模板实参实例化的函数称为模板函数。模板函数的生成就是将函数模板的类型形参实例化的过程。例如:
使用中应注意的几个问题:
⑴ 函数模板允许使用多个类型参数,但在template定义部分的每个形参前必须有关键字typename或class,即:
template<class 数据类型参数标识符1,…,class 数据类型参数标识符n>
<返回类型><函数名>(参数表)
{
函数体
}
⑵ 在template语句与函数模板定义语句<返回类型>之间不允许有别的语句。如下面的声明是错误的:
template<class T>
int I;
T min(T x,T y)
{
函数体
}
⑶ 模板函数类似于重载函数,但两者有很大区别:函数重载时,每个函数体内可以执行不同的动作,但同一个函数模板实例化后的模板函数都必须执行相同的动作。
2 函数模板的异常处理
函数模板中的模板形参可实例化为各种类型,但当实例化模板形参的各模板实参之间不完全一致时,就可能发生错误,如:
template<typename T>
void min(T &x, T &y)
{ return (x<y)?x:y; }
void func(int i, char j)
{
min(i, i);
min(j, j);
min(i, j);
min(j, i);
}
例子中的后两个调用是错误的,出现错误的原因是,在调用时,编译器按最先遇到的实参的类型隐含地生成一个模板函数,并用它对所有模板函数进行一致性检查,例如对语句
min(i, j);
先遇到的实参i是整型的,编译器就将模板形参解释为整型,此后出现的模板实参j不能解释为整型而产生错误,此时没有隐含的类型转换功能。解决此种异常的方法有两种:
⑴采用强制类型转换,如将语句min(i, j);改写为min(i,int( j));
⑵用非模板函数重载函数模板
方法有两种:
① 借用函数模板的函数体
此时只声明非模板函数的原型,它的函数体借用函数模板的函数体。如改写上面的例子如下:
template<typename T>
void min(T &x, T &y)
{ return (x<y)?x:y; }
int min(int,int);
void func(int i, char j)
{
min(i, i);
min(j, j);
min(i, j);
min(j, i);
}
执行该程序就不会出错了,因为重载函数支持数据间的隐式类型转换。
② 重新定义函数体
就像一般的重载函数一样,重新定义一个完整的非模板函数,它所带的参数可以随意。C++中,函数模板与同名的非模板函数重载时,应遵循下列调用原则:
• 寻找一个参数完全匹配的函数,若找到就调用它。若参数完全匹配的函数多于一个,则这个调用是一个错误的调用。
• 寻找一个函数模板,若找到就将其实例化生成一个匹配的模板函数并调用它。
• 若上面两条都失败,则使用函数重载的方法,通过类型转换产生参数匹配,若找到就调用它。
•若上面三条都失败,还没有找都匹配的函数,则这个调用是一个错误的调用。
- /*
- C++类模板及参数类型的运行时判断(typeid)
- */
- #include <stdio.h>
- #include <typeinfo>
- #include <vector>
- using namespace std;
- template<class T>
- class Exercise
- {
- public:
- typedef T Type;
- typedef vector < Type > VT;
- Exercise(int n);
- void Display();
- private:
- VT dv;
- };
- template<class T>
- Exercise<T>::Exercise(int n)
- {
- T v;
- printf("type: %s\n", typeid(T).name());
- for(int i = 0; i < n; i++)
- {
- v = 1.1 * (i+1);
- dv.push_back(v);
- }
- }
- template<class T>
- void Exercise<T>::Display()
- {
- char fmt[2][10] = {"%d\t", "%.2f\t"};
- char *p = fmt[0];
- if(typeid(T) == typeid(double) || typeid(T) == typeid(float))
- p = fmt[1];
- for(typename vector<T>::iterator it = dv.begin(); it != dv.end(); it++)
- {
- printf(p, *it);
- }
- printf("\n\n");
- }
- int main()
- {
- Exercise<double> ex1(5);
- ex1.Display();
- Exercise<float> ex2(5);
- ex2.Display();
- Exercise<int> ex3(5);
- ex3.Display();
- Exercise<long> ex4(5);
- ex4.Display();
- printf("\n");
- printf("%s\n", typeid(ex1).name());
- printf("%s\n", typeid(ex2).name());
- printf("%s\n", typeid(ex3).name());
- printf("%s\n", typeid(ex4).name());
- return 0;
- }
[c++][语言语法]函数模板和模板函数 及参数类型的运行时判断的更多相关文章
- XPAND模板语言语法1.0
XPAND模板语言语法1.0 Xpand模板语言一般写在以.xpt为结尾的文本文件中 ,以"« »" 作为开头和结尾 .Xpand语言主要包括以下几个标签: «IMPORT», ...
- C++函数模板&类模板
函数模板 模板概念及语法 主要目的,简化代码,减少重复代码.基本语法格式: template<class T> 或者 template<typename T> //末尾不加分 ...
- C++中的动态类型与动态绑定、虚函数、运行时多态的实现
动态类型与静态类型 静态类型 是指不需要考虑表达式的执行期语义,仅分析程序文本而决定的表达式类型.静态类型仅依赖于包含表达式的程序文本的形式,而在程序运行时不会改变.通俗的讲,就是上下文无关,在编译时 ...
- python函数参数类型及其顺序
根据inspect模块官文文档中关于函数参数类型的相关说明,python函数参数共有五种类型,按顺序分别为:POSITIONAL_ONLY.POSITIONAL_OR_KEYWORD.VAR_POSI ...
- T4学习- 3、创建运行时模板
使用 Visual Studio 预处理过的文本模板,可以在运行时在应用程序中生成文本字符串. 执行应用程序的计算机不必具有 Visual Studio. 预处理过的模板有时称为"运行时文本 ...
- C# 语言规范_版本5.0 (第4章 类型)
1. 类型 C# 语言的类型划分为两大类:值类型 (Value type) 和引用类型 (reference type).值类型和引用类型都可以为泛型类型 (generic type),泛型类型采用一 ...
- ThinkPHP第五天(提交类型判定常量IS_POST等,错误页面种类,Model实例化方式,模板中使用函数,foreach循环,模板中.语法配置)
1.IS_GET.IS_POST.IS_PUT.IS_DELETE.IS_AJAX常量,方便快捷实现各个判断. 在Action类中还可以使用$this->isPost()等进行判断. 2.错误页 ...
- C++ 函数模板一(函数模板定义)
//函数模板定义--数据类型做参数 #include<iostream> using namespace std; /* 函数模板声明 1.函数模板定义由模板说明和函数定义组成,并且一个模 ...
- [转]C++函数模板与模板函数
1.函数模板的声明和模板函数的生成 1.1函数模板的声明 函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计.它的最大特点是把函数使用的数据类型作为参数. ...
随机推荐
- websocket 待更新
https://mp.weixin.qq.com/s?__biz=MjM5OTM0MzIwMQ==&mid=2652545551&idx=1&sn=403b75d95cf191 ...
- javascript 字符串相关知识汇总
① charAt(): 选中字符串内第几个元素 <script> var str="1234567389"; alert( str.charAt(1) ); // 2 ...
- python实现跳板机
公司有1000多台服务器,线上机器都是禁止root登录的,所以平时是用普通用户登录,然后在su到root,密码都是在excel表中存的,这样登录一台机器,输两次命令,搜两次密码,实在很麻烦,有一天备份 ...
- C# 字典 Dictionary<Tkey,Tvalue>
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来.我们都知道计算机技术发展日新月异,速度惊人的快,你我稍不留神,就会被慢慢淘汰!因此:每日不间断的学习是避免被 ...
- Excessive AWR Growth From Partitioned Objects Such as SYS.WRH$_EVENT_HISTOGRAM Causing Sysaux to Grow
AWR数据增长较快,导致sysaux表空间使用较高 SQL> select f.tablespace_name, 2 a.total, 3 f.free, 4 round((f.free / a ...
- 在Entity Framework 4.0中使用 Repository 和 Unit of Work 模式
[原文地址]Using Repository and Unit of Work patterns with Entity Framework 4.0 [原文发表日期] 16 June 09 04:08 ...
- Lintcode: Search Range in Binary Search Tree
Given two values k1 and k2 (where k1 < k2) and a root pointer to a Binary Search Tree. Find all t ...
- node.js http.get 和http.post 数据
http.get('http://codestudy.sinaapp.com', function (response) {}); node.js http post 样例: var reqData= ...
- flot_js_$用法解释
$用法解释 $在JS中本身只是一个符号而异,在JS里什么也不是.但在JS应用库JQUERY的作者将之做为一个自定义函数名了,这个函数是获取指定网页元素的函数,使用非常之频繁,所以好多新手不知道,还以为 ...
- paper 37 : WINCE的BIB文件解析
WINCE的BIB文件解析 BIB的全称为Binary Image Builder,在Wince编译过程中的最后MakeImage阶段会用到BIB文件,BIB文件的作用是指示构建系统如何构建二进制映像 ...