🌈欢迎来到C++专栏~~模板进阶
- (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是Scort
- 目前状态:大三非科班啃C++中
- 🌍博客主页:张小姐的猫~江湖背景
- 快上车🚘,握好方向盘跟我有一起打天下嘞!
- 送给自己的一句鸡汤🤔:
- 🔥真正的大师永远怀着一颗学徒的心
- 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏
- 🎉🎉欢迎持续关注!
模板参数分类类型形参与非类型形参
类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。
比如我们要实现一个静态的数组
#define N 100;template
class array
{//....
private:T _a[N];
};
但是,这样无法灵活控制栈的大小 —— 不是泛型化
int main()
{array a1; //只能存100array a2; //存1000不可以return 0;
}
🧐这就要引入非类型模板参数
非类型模板参数,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用
template
class array
{//....
private:T _a[N];
};int main()
{array a0; //可以给缺省参数:从右向左缺,且连续array a1; //100array a2; //1000return 0;
}
注意:
不允许
作为非类型模板参数的(只支持整形)🥑吐槽array——>不受欢迎
array1 a0; //C++11int a1[10]; //C//真正的区别:越界的检测//函数调用[]:assert检测有没有越界a0[10];//指针的解引用 --- 抽查是否越界,只针对越界写,越界读不检查a1[10] =10;
🌊函数模板的特化步骤:
<>
struct Date
{Date(int year, int month, int day):_year(year),_month(month),_day(day){}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}private:int _year;int _month;int _day;
};// 函数模板 -- 参数匹配
template
bool Greater(T left, T right)
{return left > right;
}//特化--针对某些类型进行特殊化处理
template<>
bool Greater(Date* left, Date* right)
{return *left > *right;
}int main()
{cout << Greater(1, 2) << endl; // 可以比较,结果正确Date d1(2022, 7, 7);Date d2(2022, 7, 8);cout << Greater(d1, d2) << endl; // 可以比较,结果正确Date* p1 = &d1;Date* p2 = &d2;cout << Greater(p1, p2) << endl; // 可以比较,结果错误return 0;
}
一般情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都是将该函数直接给出,有点鸡肋的😂
特化不能单独存在,有鸡才有蛋
全特化即是将模板参数列表中所有的参数都确定化
如果数据类型T 是Date*
默认是按照地址比较的,那这样直接比较大小的结果不是我想要的,我想要按对象比较
void test_priority_queue3(){//priority_queue pq; //默认比较地址大小priority_queue, ljj::lessPDate> pq;pq.push(new Date(2022, 10, 11));pq.push(new Date(2022, 11, 11));pq.push(new Date(2022, 12, 19));pq.push(new Date(2022, 4, 10));//默认比较地址大小,若想比较日期大小,自己写仿函数while (!pq.empty()){cout << *pq.top() << endl;pq.pop();}}
上篇博客我们知道了,可以借助模板的第三个参数Compare的口子,自己写一个仿函数来实现,现在还可以提供一个新方法:针对Date*
特化
templatestruct Greater{bool operator()(const T& x1, const T& x2) const{return x1 > x2;}};template<>struct Greater{bool operator()(Date*& x1, Date*& x2) const{return *x1 > *x2;}};
注意不用仿函数了,对Date*类型进行了特殊化处理
priority_queue pq;
偏特化,是对模板参数进一步进行条件限制的
比如下面的模板类:
using namespace std;template
class Data
{
public:Data() { cout << "Data" << endl; }
private:T1 _d1;T2 _d2;
};
🥑 部分特化
将模板参数类表中的一部分参数特化。第一个随意,第二个特化指定值
// 将第二个参数特化为int
template
class Data {
public:Data() { cout << "Data" << endl; }
private:T1 _d1;int _d2;
};int main()
{Data d1; //模板// 偏特化Data d3;Data d4;return 0;
}
🔥进一步限制,只要你是指针,不管你什么类型
//两个参数偏特化为指针类型
template
class Data
{
public:Data() { cout << "Data" << endl; }private:T1 _d1;T2 _d2;
};//两个参数偏特化为引用类型
template
class Data
{
public:Data(const T1& d1, const T2& d2): _d1(d1), _d2(d2){cout << "Data" << endl;}
private:const T1& _d1;const T2& _d2;
};int main()
{Data d5;Data d6;Data d7(1,2);return 0;
}
复习地址传送门:编译链接
分离编译:一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式,此举可以帮助我们更好的维护项目,看.h
了解框架设计功能,看.cpp
了解实现细节
✅编译链接过程:
a.h a.cpp test.cpp
🔒预处理:宏替换、头文件展开、条件编译、去注释
a.i test.i
🔒编译:C ➡️ 汇编
a.s test.s
🔒汇编:汇编 ➡️ 可重定向二进制目标文件
a.o test.o
🔒链接:将多个obj文件合并成一个,并处理没有解决的地址问题
普通函数分离编译没有问题,模板函数分离编译会出现链接不上错误,分析如下 ——
原因时:在链接之前,二者并不会交互,所以头文件只有模板,T无法确定所以没有实例化,insert等就没有进符号表,链接在符号表中找不到,自然就报错
➰解决方法
🔸1. 将声明和定义不要分离到.h和.cpp,放在同一个文件中(推荐)
那么,在编译阶段,test.i中,头文件展开后,直接就有模板的定义和实例化,可以直接填上调用地址,不需要链接时去找了
🔸2.显示实例化(不推荐)
缺点:用一个就得显示实例化一个,非常麻烦,泛型失去意义
#include"a.h"void F1(int N)
{// 2.编译阶段:生成汇编代码cout << "void F1(int N)" << endl;
}template
void F2(const T& N)
{// 2.编译阶段:不处理,没有实例化,无法生成汇编代码cout << "void F2(const T& N)" << endl;
}// 显式实例化
template
void F2(const int& N);
【优点】:
【缺陷】:
广州什么时候好起来