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成员以释放该副本使用的内存: ...
随机推荐
- Javac的命令(-Xlint)
在OptionName类中的枚举定义如下: XLINT("-Xlint"), XLINT_CUSTOM("-Xlint:"), -Xlint Enabl ...
- JavaScript设计模式-6.封装
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- PHP之mb_strpos使用
mb_strpos (PHP 4 >= 4.0.6, PHP 5, PHP 7) mb_strpos - Find position of first occurrence of string ...
- bind(0)
通配地址就是全0的地址,由内核随机选取
- spring mongo data api learn
1 索引 1.1 单列索引 @Indexed @Field(value = "delete_flag") private Boolean deleteFlag = false; @ ...
- [转]OData and Authentication – Part 6 – Custom Basic Authentication
本文转自:https://blogs.msdn.microsoft.com/astoriateam/2010/07/21/odata-and-authentication-part-6-custom- ...
- [转]Web Api系列教程第2季(OData篇)(二)——使用Web Api创建只读的OData服务
本文转自:http://www.cnblogs.com/fzrain/p/3923727.html 前言 很久没更新了,之前有很多事情,所以拖了很久,非常抱歉.好了,废话不多说,下面开始正题.本篇仍然 ...
- c#尽量使用条件属性(Conditional Attribute)
至此我们应该对Attribute属性大体了解了.下面来看看条件属性(Conditional Attribute)到底是怎么回事. 1 [Conditional("DEBUG")] ...
- <深入理解JavaScript>学习笔记(1)_编写高质量JavaScript代码的基本要点
注:本文是拜读了 深入理解JavaScript 之后深有感悟,故做次笔记方便之后查看. JQuery是一个很强大的JavaScript 类库,在我刚刚接触JavaScript的就开始用了. JQuer ...
- jQuery 判断元素上是否绑定了事件
我研究了一下之后发现,jQuery都将事件缓存起来了,其实也是为了防止内存溢出以及页面unload的时候的速度,也包括多函数触发,方便管理等诸多好处,具体可以参考此文. jQuery会在window. ...