【C++】模版进阶
本文是小编巩固自身而作,如有错误,欢迎指出!
一.非参数类型模版
(1)非参数类型模版的定义
非参数类型模板(通常称为非类型模板参数)是 C++ 模板机制的一个重要特性,它允许在模板定义中使用常量表达式作为模板参数。也就是说模版参数也,可以不是类型而是值。
(2)非参数类型模版应用
但是我们为什么要使用非类型参数模版呢?
我们先看看以下代码
#define N 10
template<class T>
class stack
{
private:T _a[N];int _top;int _capacity;
};
int main()
{stack<int> s1;//10stack<int> s2;//1000,单单使用宏N无法满足创建不同容量栈的需求
}
我们通过上述代码就可以发现,我们实现这个栈的时候我们单单使用一个宏N无法满足创建不同容量栈的需求,因此我们可以使用非参数类型模版
//使用非类型模版参数
template<class T=int,size_t N=100>
class stack2
{
private:T _a[N];int _top;int _capacity;
};
二.模板特化
(1)模版特化的定义
模板特化是C++模板编程中的一个重要特性,它允许针对特定的模板参数类型提供专门的实现版本。当我们使用模板时,模板会根据传入的参数生成相应的代码,但有时候对于某些特定的参数类型,我们希望有不同的处理逻辑,这时就可以使用模板特化。
(2)模版特化的应用
那么在什么场景下我们使用模版特化呢?我们看看以下代码
template<class T>
bool Less(const T& left, const T& right)//使用&避免传值传参,同时const修饰避免使用引用将原值修改
{return left < right;
}
//特化
template<>
bool Less<double*>(double* const & left,double* const & right)//const 在*左边修饰指针指向对象,在* w右边修饰指针本身
{return *left < *right;
}
template<>
bool Less<string*>(string* const & left, string* const & right)
{return *left < *right;
}
在上述代码我们就可以发现一个问题,当我们这个比较函数比较的是int,char等类型是可以直接比较的,但是如果给定的类型是int*,string*等等,就会出现比较的是地址,而并非内容,因此,对其使用特殊化处理,也就是所谓的模版特化
(3)全特化与偏特化
3.1全特化
所谓全特化,就是将模版的每一个参数特殊化处理,而偏特化就是只处理部分参数
下面是全特化
template<class T1,class T2>
class Date
{
public:Date(){cout << "Date(T1,T2)" << endl;}
private:T1 d1;T2 d2;};
//全特化
template<>
class Date<int,char>
{
public:Date(){cout << "Date(int,char)" << endl;}
};
3.2偏特化
而偏特化就又要分为两类了,特化部分参数和对参数进一步限制
3.2.1特化部分参数
//偏特化
//特化部分参数
template<class T1>
class Date<T1,char>
{
public:Date(){cout << "Date(T1,char)" << endl;}
};
3.2.2对参数进一步限制
//偏特化
//对参数进一步限制
template<class T1,class T2>
class Date<T1*, T2*>
{
public:Date(){cout << "Date(T1*,T2*)" << endl;}
};template<class T1, class T2>
class Date<T1&, T2&>
{
public:Date(){cout << "Date(T1&,T2&)" << endl;}
};
三.模版分离编译
(1)分离编译常见的报错原因
当模板的声明和定义分离:即声明在.h文件,但是定义在.cpp文件的时候,往往会产生链接错误。因为链接时,需要通过重定位,将所遇到的标识符(如某个函数名)的地址链接上。
即如图所示
我们会发现报错了,原因是什么呢?,其实原因就在于在进行链接的时候,编译器没有没有找到实例化模版,无法对不确定的类型(上图的T)进行链接,因此无法运行。
(2)分离编译无法运行的解决方法
那我们该如何解决上述问题呢,这里提供两种思路一种是显式实例化,一种是就是直接将定义写到头文件了
2.1显示实例化
//.h
template<class T>
void funcA(const T& x);
//.cpp
template<class T>
void funcA(const T& x)
{cout << "void FuncT(const T& x)" << endl;
}
template
void funcA(const int& x);
2.2声明和定义一起放在头文件
template<class T>
void funcA(const T& x)
{cout << "void FuncT(const T& x)" << endl;
}
本次分享就到这里结束了,后续会继续更新,感谢阅读!