模板编程
函数模板
template // 模板参数列表,可以包含多个参数
bool compare(const T a, const T b)
{
return a > b;
}
模板可在编译阶段,调用点进行实例化生成模板函数,在最终一起参与编译形成一个obj文件。但模板不参与编译,如果没有调用模板函数的话,编译器是不会检查模板内的错误的。
模板可以有类型参数和非类型参数,非类型参数是一个整数,是一个常量。类型参数可以用class 和typename来修饰。
模板的实参推演,编译器可以根据传入的实参类型自动生成一个该类型的模板函数
例如
compare(10,30);
编译器会自动识别生成一个整型的模板函数,如果定义了其普通的非模板函数的话,就会调用这个普通的函数,而不会生成模板函数。
也可以隐式进行实例化
compare(10,30);
我们也可以对函数模板进行特例化,就是自己实现一个特别的例子进行实例化,而不是让模板自动生成一个模板函数;
如:
typename<>
bool compare<const char *>(const char *a,const char *b)
{
return strcmp(a,b)>0;
}
这时如果我们调用compare(“aaaa”,“bbb”);的话,就会调用这个特例化的函数而不会再按照模板内的内容就是自动生成模板函数;
模板除了进行隐式实例化之外,还有显示实例化
显示实例化可以定义为:template bool compare(int, int);
编译器会根据这个声明,生成一个整型类型的模板函数,不管该函数调没调用,和隐式实例化的区别在于,隐式实例化要在调用的时候在进行实例化,没调用就不进行实例化。
注意点:
1、模板代码不能定义在源文件当中,在另外的源文件中调用
因为如果在一个源文件中定义,在另一个源文件中调用的话,只是声明了模板。我们知道编译是一个一个文件进行编译,如果只是声明了模板而没有定义的话,在调用模板函数的时候,没有找到模板的定义,而无法生成模板函数,就会报出未定义的错误。解决方法就是在显示实例化,但如果每个都显示实例化的话,模板就没有存在的意义了。最好就是将模板的相关代码都放在一个头文件中,这样使用时就直接#include就行了。
2、 模板的代码都是放在头文件当中,在源文件中#include
容器的空间配置器 allocator
作用:
对象的内存开辟和对象构造分离开;
对象的析构和内存的释放分离开;
一共四个函数:
allocate:内存开辟
deallocate:内存释放;
construct:对象构造;
destroy:对象析构;
自定义容器空间配置器
template<typenem T>
struct mallocator
{
//内存开辟
T* allocate(size_t size)
{
return (T*)malloc(size*sizeof(T));
}
//内存释放
void dealocate(T *prtr)
{
free(ptr);
}
//对象构造
void construct(T *ptr,const T &obj)
{
new(ptr)T(obj);
}
//对象析构
void destroy(T *ptr)
{
ptr->~T();
}
}
类模板,使用容器vector和空间配置器来实现
// 类模板 vector 默认构造 size:0-1-2-4-8-16-32-64…
template<typename T=int,
typename _Alloc= myallocator<T>>
class Vector // 类的模板名字
{
public:
Vector();
~Vector();
Vector(const Vector<T> &vec);
Vector(Vector<T> &&vec);
void operator=(const Vector<T> &vec);
void operator=(Vector<T> &&vec);
void reserve(int size); // 预留函数
void push_back(const T &val); // 末尾添加元素
void pop_back(); // 末尾删除元素
bool empty()const; // 判空
bool full()const; // 判满
int size()const; // 返回vector容器元素的个数
void show()const; // 打印vector容器的所有元素
private:
T *mpvec;
int mcur;
int msize;
_Alloc malloctor; // 定义空间配置器对象
void resize(); // vector容器底层默认2倍扩容
};
template<typename T>
Vector<T>::Vector()
:mcur(-1)
, msize(0)
, mpvec(nullptr) {}
template<typename T>
Vector<T>::~Vector()
{
for (int i = 0; i < mcur; ++i)
{
// 析构容器中有效的对象
malloctor.destroy(mpvec + i);
}
// 把容器内存释放掉
malloctor.deallocate(mpvec);
mpvec = nullptr;
}
template<typename T>
Vector<T>::Vector(const Vector<T>& vec)//左值拷贝构造
{
msize = vec.msize;//空间大小
mcur = vec.mcur;//现在存的元素个数
mpvec = malloctor.allocate(msize);
for (int i = 0; i < mcur; i++)
{
malloctor.construct(mpvec + i, vec.mpvec[i]);
}
}
template<typename T>
Vector<T>::Vector(Vector<T>&& vec)
{
mpvec = vec.mpvec;
vec.mpvec = nullptr;
mcur = vec.mcur;
msize = vec.msize;
}
template<typename T>
void Vector<T>::operator=(const Vector<T>& vec)
{
if (this == &vec)
{
return;
}
for (int i = 0; i < mcur; i++)
{
malloctor.destory(mpevc + i)
}
malloctor.deallocate(mpevc);
msize = vec.msize;//空间大小
mcur = vec.mcur;//现在存的元素个数
mpvec = malloctor.allocate(msize);
for (int i = 0; i < mcur, i++)
{
malloctor.construt(mpevc + i, vec.mpvec[i]);
}
}
template<typename T>
void Vector<T>::operator=(Vector<T>&& vec)
{
if (this == &vec)
{
return;
}
for (int i = 0; i < mcur; i++)
{
malloctor.destory(mpvec + i);
}
malloc.deallocate(mpvec);
msize = vec.msize;
mcur = vec.mcur;
mpvec = vec.mpvec;
vec.mpvec = nullptr;
}
template<typename T>
void Vector<T>::reserve(int size)
{
if (size <= msize)
return;
T* ptmp = malloctor.allocate(size);
for (int i = 0; i < mcur; ++i)
{
malloctor.construct(ptmp + i, mpevc[i]);
}
for (int i = 0; i < mcur; i++)
{
malloctor.destory(mpevc + i);
}
malloctor.deallocate(mpevc);
mpvec = ptmp;
msize = size;
}
template<typename T>
void Vector<T>::push_back(const T & val)//尾部添加
{
if (full())
{
resize();
}
mcur++;
alloctor(mpevc + mcur, val);
}
template<typename T>
void Vector<T>::pop_back()//尾部删除
{
if (empty())
{
return;
}
malloctor.destory(mpevc + mcur);
mcur--;
}
template<typename T>
bool Vector<T>::empty() const
{
return mcur == 0;
}
template<typename T>
bool Vector<T>::full() const
{
return mcur == msize;
}
template<typename T>
int Vector<T>::size() const
{
return mcur;
}
template<typename T>
void Vector<T>::show() const
{
for (int i = 0; i < mcur; i++)
{
cout << mpvec[i] << " ";
}
cout << endl;
}
template<typename T>
void Vector<T>::resize()//扩容
{
if (msize > 0)
{
T *ptmp = malloctor.allocate(msize * 2);
for (int i = 0; i < msize; i++)
{
malloctor.construct(ptmp + i, mpvec[i]);
// 析构容器中有效的对象
malloctor.destroy(mpvec + i);
}
// 把容器内存释放掉
malloctor.deallocate(mpvec);
mpvec = ptmp;
ptmp =
msize *= 2;
}
else
{
mpvec = malloctor.allocate(1); // size * sizeof(T)
msize = 1;
mcur = 0;
}
}