之前我们就讲过一小部分的模板

接下来我们更加深入的了解一下模板

这里我们要创建一个静态的栈通常是下面这个样子

但是我们要进一步考虑我们要是申请栈的大小是不一样的情况该怎么半办呢?要是初始的内存给小了不够用,给大了用不完,还会造成浪费

这时候就要使用到我们的函数模板--非类型函数模板

当然我们也要想一下有关于缺省值的事

缺省值给的话要从后往前给,可以全给也可以只给一部份

上面说的非类型模板在c++的容器上面也是有应用的也就是array

在很大程度上array和数组是十分相似的

没给数据时

给了数据时

但是array在某种程度上比数组更好一些

比如对于越界的问题

数组的越界检查时一种抽查行为,有时候可以检查出来有时候却又是不行的,但是array是一定可以给你检查出来的。

接下来我们来了解一下函数模板特化

我们先来看一个普通的

但是如果我们想要用指针来比较

这时候就会出现问题,因为指针是new出来的新对象的地址,是不确定的我们要求的也是他解引用之后的结果比较。

这个时候特化就派上了用场

特化的写法

特化的函数模板是基于普通的函数模板,不能没有普通的函数模板。

但是但看上面那个less的实现还是有问题的

T在拷贝的时候花费会巨大所以我们要用引用,为了防止误操作也要加上const。

但是当我修改完却又发现说这个不是函数模板的特化。

其根本原因是我们const和*之间的关系问题。

你搞的清楚这三者之间的区别吗?

const在*的左边是指向的内容不能改变

const在*的右边是指针不能改变

在修改后就可以成功运行

当然还有类模板的特化

全特化

是指定模板参数的具体类型,为这种特定组合提供完全独立的实现。它是对模板参数“全部”确定的特化。

在类名后面加上具体的类型,如果全都是具体的类型就是全特化,如果有一部风份还是模板

就是偏特化。

偏特化

值得注意的是模板的不管是全特化还是偏特化相较于原来的模板都是一个崭新的类,其内部的成员函数和成员变量都是可以不同的。下图中d1没有print,d2,d3都由print那么在函数实例化之后就可以调用成员函数来实现不通的功能

        

template<class T1, class T2>
class Data
{
public:
	Data() { cout << "Data<T1, T2>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};

//全特化
template<>
class Data<string,string>
{
public:
	Data() { cout << "Data<string,string>" << endl; }

	void print()
	{
		cout << "hello world" << endl;
	}
private:
	string s1="111111";
};


//偏特化
template<class T1 >
class Data<T1,int >
{
public:
	Data() { cout << "Data<T1,int >" << endl; }

	void print()
	{
		cout << "Data<T1,int >,not Data<T1,T2 >" << endl;
	}
private:
	
};


int main()
{
	Data<char,char> d1;
	Data<string,string> d2;
	Data<char, int> d3;
	d2.print();
	d3.print();

	return 0;

}

当然特化也不仅仅可以针对类型,可以是指针也可以是用引用。

当然也是可以交叉使用

通过观察呢也可以看出他的匹配原则实际上就是匹配在<>内部的。


通过以上内容的学习,就可以来解决上一章priority_queue那章date的问题

用指针的时候,比较地址是无法来满足我们的需求

我们在上一章采用仿函数的解决方案

现在我们用模板的特化来解决问题

我们对less进行特化来解决

理解为什么模板在使用时不要将定义是声明分离XX.h和XX.cpp?

首先我们要先回顾一下在inline那章的内容,理解预处理,编译,汇编,链接运行的原理

接下里我们看一个代码然后进一步理解

如果我们要进行函数的声明和定义分离·

普通函数声明定义分离

函数模板:定义和声明分离

无法找到特化的函数,

我们先来看普通的函数是如何成功完成这个操作

函数编译后会生成多条指令,其中第一条指令即为函数地址。

对于声明和定义分离的函数,编译后仅包含函数声明,不包含实际地址。

函数调用通过call指令实现(地址调用)。当函数只有声明时,编译可通过语法检查,但在链接阶段会因找不到函数地址而报错。

函数模板声明与定义分离时为何报错?

关键在于函数模板的实例化:主函数虽能推导出intdouble等模板类型,但无法将该信息传递至包含函数定义的文件,导致无法生成对应的实例化函数。最终在链接阶段因找不到具体实现而报错。

那么我们知道原理之后我们就可以采用显示实例化来解决

但是这样就失去模板函数的风格和特点,在实践中是不建议这个样子来解决问题的

还是推荐模板函数的定义和声明都采用在xx.h文件中完成。

更多推荐