news 2026/5/25 11:32:36

C++模板特化:类型与常量的灵活掌控

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++模板特化:类型与常量的灵活掌控

一、模板参数再介绍

初级模板知识

模板参数是一个用来存放类型名称(int double
等内置类型和自定义类型名称)的变量。在代码实现中使用模板参数写代码(写一个函数或类),会增加代码复用的能力。
写出的函数或类被称为函数模板和类模板。 模板实例化:编译器根据使用模板时指定的类型名称,用这个类型名称来替代模板参数,生成相应的函数或类。
使用函数模板时,通过传入参数类型实例化出相应的模板。 而使用类模板时,需要显示说明模板参数类型,才能实例化出相应的类。

二、非类型模板参数

前面提及的模板参数接受的都是类型的名字,还有一种模板参数接受的是一个常数。
看下面一段代码:

#include<iostream>template<classT,size_t size=10>classarr{private:T arr[size];intlen=size;public:arr();~arr();T&operator[](constarr&a);boolempty();};

这个是C++STL中对数组的改造array的模拟实现(未完成),与c风格数组相比,容器arr对越界访问更加严格。我们看到arr是一个类模板,有两个模板参数,第二个模板参数就是上面提及的非类型模板参数,相当于C语言中常量的宏定义。
但与宏定义相比较,这样的类模板可以根据传入参数的不同自动调整常量,不需要改变代码,但是宏定义恰恰相反。

举个arr的使用例子来体会非类型模板参数的用途:

#include<iostream>usingnamespacestd;#include<array>intmain(){array<int,20>arr={1,2,3,4,5};for(inti=0;i<arr.size();i++){cout<<arr[i]<<" ";//1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}cout<<endl;return0;}

三、函数模板的特化

为什么需要引入特化
就函数模板而言:由于所有符合函数模板的参数列表中的每组参数并不都要根据函数模板实例化出的函数进行运算,总有一两个特例要实现不同的方法,所以引入模板特化。比如我想实现一个函数,当两个参数是一切参数时,判断第一个参数是否大于第二个参数。如果这样实现:

#include<iostream>usingnamespacestd;template<classT>boolfun(T a,T b){returna>b}intmain(){inta=10,b=20;int*pb=&b,*pa=&a;cout<<fun(a,b)<<endl;cout<<fun(pa,pb)<<endl;}

存在指针比较,是不是没有任何意义,当参数为int*时,我们特化一个函数模板,让它返回指针所指向的最大的数:

#include<iostream>usingnamespacestd;template<classT>boolfun(T a,T b){returna>b}template<>boolfun<int*>(int*a,int*b){return*a>*b;}intmain(){inta=10,b=20;int*pb=&b,*pa=&a;cout<<fun(a,b)<<endl;cout<<fun(pa,pb)<<endl;}

函数模板特化的语法:
1.前提是有一个相关的函数模板
2.在特化函数模板之前加上template<>
3.在特化声明函数时在函数名之后参数表之前加上<特化的类型名称>
4.要求函数的其余部分除将模板参数特化替代外,必须和原来函数一模一样否则,就会编译报错。
函数模板特化的特点:
由于函数模板的性质,当定义一个将函数模板中所有模板参数替代成统一类型名称的函数fun时,调用一个既可以走函数模板,又可以直接调用fun时,编译器会不再实例化函数模板,直接调用fun。因此函数模板特化的作用不大,大多数情况都可以通过定义一个将函数模板中所有模板参数替代成统一类型名称的函数fun,调用fun直接解决问题,但也不排除只有使用函数模板特化的方法才能解决问题的项目。

使用上面提及的第二种常规方法解决之前需要函数模板特化才可以解决的问题:

#include<iostream>usingnamespacestd;template<classT>boolfun(T a,T b){returna>b;}boolfun(int*a,int*b){return*a>*b;}intmain(){inta=10,b=20;int*pb=&b,*pa=&a;cout<<fun(a,b)<<endl;cout<<fun(pa,pb)<<endl;}

四、类模板的特化

1.全特化
顾名思义就是将所有参数都特化,和函数模板特化一样,这里也强调一下:函数模板特化的方式只有一种,类模板特化可以全特化,也可以半特化。
示例代码:

#include<iostream>usingnamespacestd;template<classT1,classT2>classc1{private:T1 t1;T2 t2;public:c1(){cout<<"T1,T2"<<endl;}};template<>classc1<int,int>{private:intt1;intt2;public:c1(){cout<<"int ,int "<<endl;}};intmain(){c1<int,double>cc;c1<int,int>c1;//T1,T2//int, int}

和函数模板特化一致,特化定义前要加上template<>
特化声明时l类的名字和{}之间要加上<特化的类型名称>
2.半特化(别称:偏特化)
先来看一下半特化的代码演示:

#include<iostream>usingnamespacestd;template<classT1,classT2>classc1{private:T1 t1;T2 t2;public:c1(){cout<<"T1,T2"<<endl;}};template<classT1>classc1<T1,int>{private:T1 t1;intt2;public:c1(){cout<<"T1 ,int "<<endl;}};intmain(){c1<int,double>cc;c1<int,int>c1;//T1,T2//T1, int}

半特化和全特化的不同在于:半特化定义之前,加的是template<未特化的模板参数声明>特化时类名称和{}之间加的是<未特化的模板参数,特化的模板参数>(这个排序要求和类模板定义之前的模板参数声明要一一对应下面的例子就是最好的说明)

#include<iostream>usingnamespacestd;template<classT1,classT2,classT3>classc1{private:T1 t1;T2 t2;T3 t3;public:c1(){cout<<"T1,T2,T3"<<endl;}};template<classT1,classT3>classc1<T1,int,T3>{private:T1 t1;intt2;public:c1(){cout<<"T1 ,int,T3 "<<endl;}};intmain(){c1<int,double,int>cc;c1<int,int,double>c1;/*T1, T2, T3 T1, int, T3*/}

半特化还有一种特殊的例子,当被特化的类未指针或引用时:

template<classT1,classT2>classData{public:Data(){cout<<"Data<T1, T2>"<<endl;}private:T1 _d1;T2 _d2;}//两个参数偏特化为指针类型template<typenameT1,typenameT2>classData<T1*,T2*>{public:Data(){cout<<"Data<T1*, T2*>"<<endl;}private:T1 _d1;T2 _d2;};//两个参数偏特化为引用类型template<typenameT1,typenameT2>classData<T1&,T2&>{public:Data(constT1&d1,constT2&d2):_d1(d1),_d2(d2){cout<<"Data<T1&, T2&>"<<endl;}private:constT1&_d1;constT2&_d2;};voidtest2(){Data<int,double>d2;// 调用基础的模板Data<int*,int*>d3;// 调用特化的指针版本Data<int&,int&>d4(1,2);// 调用特化的指针版本}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/25 11:31:02

如何用GetQzonehistory完整备份你的QQ空间记忆:终极免费指南

如何用GetQzonehistory完整备份你的QQ空间记忆&#xff1a;终极免费指南 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否还记得QQ空间里那些珍贵的青春记忆&#xff1f;从第一条青…

作者头像 李华
网站建设 2026/5/25 11:30:34

2026必备!AI论文写作工具测评:最新最全推荐与对比

2026年真正好用的AI论文写作工具&#xff0c;核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测&#xff0c;千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队&#xff0c;覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一…

作者头像 李华
网站建设 2026/5/25 11:26:23

推荐长沙的全屋智能家居实体店

痛点深度剖析我们团队在实践中发现&#xff0c;全屋智能家居行业存在诸多技术困境。客户在实操过程中&#xff0c;常遇到设备不兼容问题&#xff0c;不同品牌设备难以实现无缝联动&#xff0c;导致智能场景无法稳定运行。例如&#xff0c;一些拼凑式智能系统&#xff0c;因缺乏…

作者头像 李华
网站建设 2026/5/25 11:24:52

百考通AI助你把教育理想转化为可行方案

开题报告是学术研究的“第一张路线图”&#xff0c;它不仅决定你的选题能否通过&#xff0c;更直接影响后续论文的逻辑性、深度与完成质量。然而&#xff0c;许多学生在撰写时常常感到力不从心&#xff1a;问题意识模糊、文献堆砌无主线、研究方法空泛、结构松散不规范……这些…

作者头像 李华