C++ Primer(6) 模板和泛型编程(上)
泛型编程是独立于变量类型的方式编写代码;模板是泛型编程的基础。本篇主要介绍模板的基础知识,包括:模板的定义和模板的实例化。
1 模版定义
int compare(const string &v1, const string &v2)
{
if ( v1 < v2 ) return -1;
if ( v2 < v1 ) return 1;
return 0;
} int compare(const double &v1, const double &v2)
{
if ( v1 < v2 ) return -1;
if ( v2 < v1 ) return 1;
return 0;
}
很明显地看到,上面的两个函数几乎相同,事实上我也是复制第一个函数,然后修改参数类型作为第二个函数的。
template <typename T>
int compare(const T &v1, const T &v2)
{
if ( v1 < v2 ) return -1;
if ( v2 < v1 ) return 1;
return 0;
}
定义: template + 模版形参列表
模板形参列表是用尖括号括住的一个或多个模板形参(可以表示类型的类型形参,也可以表示常量表达式的非类型形参)的列表,形参之间用逗号隔开。类型形参跟在关键字class, typename之后定义class和typename没有区别。
使用:
int main()
{
// 模板形参为int
cout << compare(1, 0) << endl;
// 模板形参为string
string s1 = "hi", s2 = "world";
cout << compare(s1, s2) << endl;
return 0;
}
注意:inline模板函数的inline关键字要放在摸板型列表之后,返回类型之前,不能放在关键字template之前。
template <class Type>
class Queue {
public:
Queue();
Type &front();
const Type &front () const;
void push (const Type &);
void pop();
bool empty() const;
};
Queue<int> qi; //用int代替Type
Queue< vector<double> > qc; //用 double型的vector代替Type
Queue<string> qs; //用string代替Type
从声明为模版形参到模板声明或定义的末尾处使用。
屏蔽全局名字
Demo
typedef double T;
......
template <class T>
T calc (const T &a, const T &b)
{
T tmp = a;
....
return tmp;
}
T定义为double的全局类型别名将被名为T的类型形参所屏蔽。
限制:模版形参的名字只能在同一模板形参表中使用一次,且不能在当前模板内部重用,但是可以在不同的模板中重用。
template <typename T, size_t N>
void array_init(T array_init(T (&parm)[N])
{
for (size_t i = 0; i != N; ++i)
{
parm[i] = 0;
}
} // 调用,当调用array_init时,编译器从数组实参计算非类型形参的值
int x[42];
double y[10];
array_init(x); // 等效 <int, 42>
array_init(y); // 等效 <double, 10>
- 模板的形参是const引用:允许使用不允许复制的类型
- 函数体中的测试只用<比较:减少对类型的要求(可能会有些类型,支持'<'但不支持'>')。
//用string类型的对象创建Queue类
Queue<string> qs; // stirng代替Type的每次出现
函数模板实例化:编译器通常会为我们推断模板实参
int main()
{
compare(1, 0);
comapre(3.14, 2.7);
}
模板实参推断
只有两种情况会发生实参以匹配已有的实例化:
const转换:接受const引用或const指针的函数可以分别用非const对象的引用或指针来调用,无需产生新的实例化。
数组或函数到指针的转换:对数组或函数类型的实参用常规的指针转换。
template <typename T> // 值传递
Tfobj(T, T);
template <typenam T>
T fref(const T&, const T&); // 引用传递 string s1("a value");
const string s2("another value");
fobj(s1, s2); // ok,const属性被忽略
fref(s1, s2); // ok , s1转换为const引用 int a[10], b[42];
fobj(a, b); // ok,数组转换为指针
fref(a, b); // error,形参为引用,数组不能转换为指针
template <typename T> int compare(const T&, const T&);
// pf1指向该模版函数的int型实例的地址
int (*pf1) (const int&, const in&) = compare;
指针pf1引用的是将T绑定到int的实例化。
template <class T class U> ??? sum(T, U); // 无法确定合适的返回类型
sum(2, 4L); // 适合该调用的为: U sum(T,U);
sum(3L, 4)); // 适合该调用的为:T sum(T, U); // 解决方案:在调用时,进行强制类型转换
int i; short s;
sum( static_cast<int>(s), i);
template <typename T1, typename T2, typename T3>
T1 sum(T2, T3); // 调用,需要显式指定返回值的类型
long val3 = sum<long>(i, lng); // 还需要注意模版形参的顺序
template <typename T1, typename T2, typnename T3>
T3 sum(T1, T2)
// 在这种情况下的调用需要从左到右依次显式指定
long val2 = sum<int, long, long>(i, lng)
template <typename T>
int compare(const T&, const T&); // 实例化
void func(int(*) (const string&, const string&));
void func(int(*) (const int&, const int&));
// 显示指明哪一个func
func(compare<int>)(1, 2);
C++ Primer(6) 模板和泛型编程(上)的更多相关文章
- C++ Primer 笔记——模板与泛型编程
1.编译器用推断出的模板参数来为我们实例化一个特定版本的函数. 2.每个类型参数前必须使用关键字class或typename.在模板参数列表中,这两个关键字含义相同,可以互换使用,也可以同时使用. t ...
- C++ primer 模板与泛型编程
继续浏览c++ primer 看到模板与泛型编程这章.就顺便把这几节的代码综合了下,对一个Queue队列模板的实现 贴一下代码(看完书.自己敲,忘记了哪再看下书) #include <ostre ...
- C++ Primer 学习笔记_76_模板与泛型编程 --模板定义[续]
模板与泛型编程 --模板定义[续] 四.模板类型形參 类型形參由keywordclass或 typename后接说明符构成.在模板形參表中,这两个keyword具有同样的含义,都指出后面所接的名字表示 ...
- C++ Primer 学习笔记_77_模板与泛型编程 --实例化
模板与泛型编程 --实例化 引言: 模板是一个蓝图,它本身不是类或函数.编译器使用模板产生指定的类或函数的特定版本号.产生模板的特定类型实例的过程称为实例化. 模板在使用时将进行实例化,类模板在引用实 ...
- C++ Primer 学习笔记_75_模板与泛型编程 --模板定义
模板与泛型编程 --模板定义 引言: 所谓泛型程序就是以独立于不论什么特定类型的方式编写代码.使用泛型程序时,我们须要提供详细程序实例所操作的类型或值. 模板是泛型编程的基础.使用模板时能够无须了解模 ...
- C++ Primer 学习笔记_76_模板和泛型编程 --模板定义[继续]
模板和泛型编程 --模板定义[续] 四.模板类型形參 类型形參由keywordclass或 typename后接说明符构成.在模板形參表中,这两个keyword具有同样的含义,都指出后面所接的名字表示 ...
- C++ Primer 学习笔记_79_模板与泛型编程 --模板编译模型
模板与泛型编程 --模板编译模型 引言: 当编译器看到模板定义的时候,它不马上产生代码.仅仅有在用到模板时,假设调用了函数模板或定义了模板的对象的时候,编译器才产生特定类型的模板实例. 一般而言,当调 ...
- C++ Primer 学习笔记_84_模板与泛型编程 --模板特化
模板与泛型编程 --模板特化 引言: 我们并不总是能够写出对全部可能被实例化的类型都最合适的模板.某些情况下,通用模板定义对于某个类型可能是全然错误的,通用模板定义或许不能编译或者做错误的事情;另外一 ...
- C++ Primer 学习笔记_85_模板与泛型编程 --模板特化[续]
模板与泛型编程 --模板特化[续] 三.特化成员而不特化类 除了特化整个模板之外,还能够仅仅特化push和pop成员.我们将特化push成员以复制字符数组,而且特化pop成员以释放该副本使用的内存: ...
随机推荐
- Mac 提交代码到Github
然后在GitHub上创建版本库(Repository),在GitHub首页上,点击“Create a New Repository”,如下所示(为了便于后面演示,创建README.md这步暂不勾选): ...
- 入门系列之在Ubuntu 14.04上备份,还原和迁移MongoDB数据库
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由信姜缘 发表于云+社区专栏 MongoDB是最受欢迎的NoSQL数据库引擎之一.它以可扩展,强大,可靠和易于使用而闻名.在本文中,我们 ...
- bzoj 4561: [JLoi2016]圆的异或并
Description 在平面直角坐标系中给定N个圆.已知这些圆两两没有交点,即两圆的关系只存在相离和包含.求这些圆的异或面 积并.异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个 ...
- JS实现图的创建和遍历
图分为无向图和有向图 图的存储结构有邻接矩阵.邻接表.十字链表.邻接多重表这四种,最常用的是前两种 本篇主要是利用邻接矩阵实现无向图的创建和遍历(深度优先.广度优先),深度优先其实就是二叉树里的前序遍 ...
- C#Json数据类型
引用所对应框架的类库文件,下载地址:http://json.codeplex.com/ 在一般处理程序axhx中: 引用的命名空间: using System.IO;using Newtonsoft. ...
- [javaSE] IO流(FIle对象递归文件列表)
获取File对象,new出来,构造参数:String目录名 调用File对象的list()方法,获取String[]数组文件名称 循环数组,列出所有文件包含隐藏文件 递归列出所有的数据 定义一个静态方 ...
- 撩课-Java每天5道面试题第12天
91.如何提升数据查询的效率? 1.首先检查表的结构是否合理, 因为采用多表查询的时候, 看主外键的引用关系是否适当. 如果不适当则重新设置表结构. 如果是应用中的系统, 则不需要更改表的字段, 只更 ...
- uestc Another LCIS
Another LCIS Time Limit: 1000 ms Memory Limit: 65536 kB Solved: 193 Tried: 2428 Description For a se ...
- bnu 被诅咒的代码
http://www.bnuoj.com/bnuoj/problem_show.php?pid=10792 被诅咒的代码 Time Limit: 1000ms Memory Limit: 65536K ...
- Line Numbers for RichText Control in C#
from: http://www.codeproject.com/Articles/38858/Line-Numbers-for-RichText-Control-in-C using Microso ...