news 2026/5/28 3:13:57

c++模板进阶知识讲解(对模板的进一步的运用与理解)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
c++模板进阶知识讲解(对模板的进一步的运用与理解)


非类型模板参数

模板参数分类类型形参与非类型形参。
类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。
非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。

这种应用场景可以用在你如果要定义的对象是静态变量就可以考虑使用,比如:静态数组

template<classT,size_t N=10>classArray{public://......一些函数private:T*_a[N];size_tsize();};

如上实例中定义的类里的模板参数里N就是非类型模板参数,它的类型一般是整型,浮点数与类类型都不行,到c++20才支持。 这种静态数组的类在STL容器的array中是使用的,它的里面的数组就是静态数组 https://legacy.cplusplus.com/reference/array/array/?kw=array 这是在cplusplus上的详细对array的内容,与vector的区别就是它的数组是定长的。

模板的特化

函数模板的特化

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板

template<classT>boolLess(constT&left,constT&right){returnleft<right;}



比如这是用来比较的函数模板,对于传入的为非指针的类型,比较逻辑不变,但如果是传入指针类型的话,这个模板实例化之后就是比较两个指针的大小在一般情况下是毫无意义的

cout<<Less(1,2)<<endl;double*p1=newdouble(2.5);double*p2=newdouble(4.9);cout<<Less(p1,p2)<<endl;

比如这里的p1与p2的比较比较最后比较的是指针的大小,而不是它们的指针指向的内容的比较,这种比较是无意义的

template<>boolLess<double*>(double*const&left,double*const&right){return*left<*right;}

这里的语法就是写个模板但是不带任何参数,这就是模板特化也叫做全特化,然后类名跟定义的参数是一样的然后尖括号里面带具体类型,比如这里是double* 函数体要接受的 形参也是尖括号里的类型,然后用解引用后的内容比较,它调用函数就会找最匹配的函数模板,第一个输出会找初始的那个,第二个会找刚刚写的特化的那个
写特化的函数模板一定要先有初始的写的不是具体类型的模板,否则就会报错,要先有这个才能写后面具体类型的模板特化

类模板的特化

全特化

跟函数模板的语法类似也是template<>

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

比如如上的一个简单的类模板,如果要写它的全特化就是

`template<>classData<int,char>{public:Data(){cout<<"Data<int, char>"<<endl;}private:int_d1;char_d2;};`

全特化就是<>里面不带任何参数而且写的特化后的模板里面的除了类名要一样,其他的比如成员变量和成员函数都可以不一样甚至可以不写都行,如果定义的对象的类型与特化的更匹配就会调用特化的类进行构造,否则就会使用最初的类模板进行构造,两者是互不干扰的,但是必须要先有类模板才有后面的特化模板
这里自己可以尝试一下然后调试写不同类型会调用那个类去构造

偏特化

意思为对部分模板参数进行具体类型显示

比如:

template<classT1,classT2>classData{public:Data(){cout<<"Data<T1, T2>"<<endl;}private:T1 _d1;T2 _d2;};// 将第二个参数特化为inttemplate<classT1>classData<T1,int>{public:Data(){cout<<"Data<T1, int>"<<endl;}private:T1 _d1;int_d2;};

保留第一个参数,显示具体类型第二个参数,如果将第一个显示具体化那就在就行后面类名跟的尖括号也要变

特别重要的一种:
如果对指针类型进行偏特化,因为我们想要的函数一般不会直接返回指针比较的值,所以可以如下这样写:

template<classT1,classT2>classData<T1*,T2*>{public:Data(){cout<<"Data<T1*, T2*>"<<endl;}};intmain(){Data<int*,int*>d1;

这里的T1和T2的实例化类型都是int 而不是int* 这是编译器的特殊处理这样会给用户的体验更好,,因为如果是int* 那类名中的就是二级指针对二级指针的操作又很麻烦,所以这里就这样处理后,对一级指针的操作不管是比较还是什么都很方便

举个应用场景:

在我们以前学的优先级队列——priority_queue中,我们的类模板参数中有默认的仿函数来做比较堆中的父子与孩子结点的优先级

template<classT>//仿函数的应用structless{booloperator()(constT&x,constT&y){returnx<y;}};template<classT,classcontainer=std::vector<T>,classCompare=less<T>>classpriority_queue{..........};

我们默认是建大堆出优先级高的数据,现在我创建个对象里面装的数据是日期类型的值

priority_queue<Date*>q1;q1.push(newDate(2026,4,10));q1.push(newDate(2026,4,11));q1.push(newDate(2026,4,12));while(!q1.empty()){cout<<*q1.top()<<" ";q1.pop();}

如果我们这样比较就是比较指针的排序,我们要的是根据日期的大小的来出列,所以我们要偏特化仿函数模板来针对这个来写:

template<classT>//仿函数的应用structless{booloperator()(constT&x,constT&y){returnx<y;}};template<classT>structless<T*>{booloperator()(T*const&x,T*const&y){return*x<*y;}};

所以当时传的是指针类型的日期就会走偏特化模板 然后里面的比较就会走它的类里的 < 的比较方式,最后就是排序就会是从大到小的输出:

模板分离编译

我们之前提过在有模板的函数里不能做函数的声明与定义,会发生链接错误。
函数的执行会通过这几个过程 预处理——编译——汇编——连接
在main()函数中调用普通函数最先会在一般是在.h文件里有函数的声明,它会在预处理展开头文件,它要call函数的地址在编译层面,他会在定义的函数里取一般是第一行执行命令的地址但你有函数的声明就相当于向编译器保证有函数的定义,所以它会去其他文件里找,找到就call 地址后 连接是与头文件连接
如果是带有函数模板的类或函数的话,首先在头文件里找到声明,然后去其它文件找定义,但是其它文件的定义都是未实例化的函数不是你传的实参的类型的参数它是一个泛型的,所以就找不到定义也就是call 中没有地址返回给它,最后在连接的时候就会报错,但也有种方法就是显示实例化对象,比如你传的是int类型,就显示写 如下:

test.h文件 test.cpp文件template<classT>voidfun(T x){.........}template<classT>template<classT>voidfun(T x);voidefun(intx);

但是这样你每传个不同类型的参数都要再写一遍显示的实例化,所以就很麻烦,所以不推荐这样写,解决办法就是:将声明和定义放到一个文件 “xxx.hpp” 里面或者xxx.h其实也是可以的
https://blog.csdn.net/pongba/article/details/19130 更详细的讲解请看这位大佬的解释

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/28 2:57:46

Spring AI 和 LangChain4j 中文档处理功能对比

前面几篇文章分别介绍了 Spring AI 和 LangChain4j 在 RAG 文档处理各环节的支持——文档读取、解析、分段、清洗、元数据加工。本文将这些知识点汇总到一个完整的对比框架中&#xff0c;以《仙逆》知识库构建为参考场景&#xff0c;帮助你在项目起始阶段快速判断哪个框架更适合…

作者头像 李华
网站建设 2026/5/28 2:51:59

Dropbox CEO 德鲁·休斯顿掌舵 19 年后卸任,将投身人工智能创业

要点 Dropbox CEO 德鲁休斯顿 24 岁创立该云存储公司&#xff0c;计划卸任 CEO 转任执行董事长。阿什拉夫阿尔卡米将从产品主管晋升为联合 CEO&#xff0c;先与休斯顿共事&#xff0c;最终独自接任 CEO 职位。休斯顿接受采访谈及卸任决定时称“从来没有一个完美的时机”。 本文…

作者头像 李华
网站建设 2026/5/28 2:48:16

AI写论文的宝藏工具!4款AI论文生成神器,为你的论文加分!

AI论文生成工具评测 在2025年&#xff0c;随着学术写作日益智能化&#xff0c;越来越多的人开始使用AI写论文的工具来撰写学术文章。很多AI论文生成工具在处理硕士和博士这样的大篇幅论文时&#xff0c;常常面临着理论深度不足和逻辑结构松散的问题。这使得许多普通的AI写论文…

作者头像 李华