C++——模板特化和偏特化

2023-10-27

1.引言
C++中的模板分为类模板和函数模板,虽然它引进到C++标准中的时间不是很长,但是却得到了广泛的应用,这一点在STL中有着充分的体现。目前,STL在C++社区中得到了广泛的关注、应用和研究。理解和掌握模板是学习、应用和研究以及扩充STL的基础。而STL模板实例中又充斥着大量的模板特化和偏特化。


2.模板的定义
(1) 类模板
定义一个栈的类模板,它可以用来容纳不同的数据类型
说明如下:
template <class T>
class stack {
private:
  list* top;
public:
  stack();
  stack(const stack&);
  ~stack();
  void push(T&);
  T& pop();
  //…
};
上述定义中,template告诉编译器这是一个模板,尖括号中的<class T >指明模板的参数,可以有一个或多个,具体实现时由用户指定,其中template <class T >中的关键字class可以用关键字typename来代替。
类模板的使用除了要在声明时指明模板参数外,其余均与普通的类相同,例如:
stack<int> int_stack;
stack<char> ch_stack;
stack<string> str_stack;
int_stack.push(10);
ch_stack.push(‘z’);
str_stack.push(“c++”);
(2)函数模板
假设现在要定义一个max函数来返回同一类型(这种类型是允许比较的)两个值的最大者.
template<class T>
T mymax(const T& t1,const T& t2)
{ return t1 < t2 ? t2 : t1; }
template <class T>的意义与类模板定义中相同。
模板函数的使用与普通非模板函数使用相同,因为模板函数的参数可以从其传入参数中解析出来。例如:
int highest = mymax(5,10);
char c = mymax(‘a’, ’z’);
mymax(5,10)解析出模板函数参数为int, mymax(‘a’, ’z’)解析出模板函数的参数为char。


3.模板的特化
(1)类模板特化
有时为了需要,针对特定的类型,需要对模板进行特化,也就是特殊处理.例如,stack类模板针对bool类型,因为实际上bool类型只需要一个二进制位,就可以对其进行存储,使用一个字或者一个字节都是浪费存储空间的.
template <class T>
class stack {};
template < >
class stack<bool> { //…// };
上述定义中template < >告诉编译器这是一个特化的模板。
(2) 函数模板的特化
看下面的例子
main()
{
  int highest = mymax(5,10);
  char c = mymax(‘a’, ’z’);
  const char* p1 = “hello”;
  const char* p2 = “world”;
  const char* p = mymax(p1,p2);
}
前面两个mymax都能返回正确的结果.而第三个却不能,因为,此时mymax直接比较两个指针p1 和 p2 而不是其指向的内容.
针对这种情况,当mymax函数的参数类型为const char* 时,需要特化。
template <class T>
T mymax(const T t1, const T t2)
{
   return t1 < t2 ? t2 : t1;
}

template <>
const char* mymax(const char* t1,const char* t2)
{
   return (strcmp(t1,t2) < 0) ? t2 : t1;
}
现在mymax(p1,p2)能够返回正确的结果了。


4.模板的偏特化
模板的偏特化是指需要根据模板的某些但不是全部的参数进行特化
(1) 类模板的偏特化
例如c++标准库中的类vector的定义
template <class T, class Allocator>
class vector { // … // };
template <class Allocator>
class vector<bool, Allocator> { //…//};
这个偏特化的例子中,一个参数被绑定到bool类型,而另一个参数仍未绑定需要由用户指定。
(2) 函数模板的偏特化
  严格的来说,函数模板并不支持偏特化,但由于可以对函数进行重载,所以可以达到类似于类模板偏特化的效果。
  template <class T> void f(T);  (a)
  根据重载规则,对(a)进行重载
  template < class T> void f(T*);  (b)
  如果将(a)称为基模板,那么(b)称为对基模板(a)的重载,而非对(a)的偏特化。C++的标准委员会仍在对下一个版本中是否允许函数模板的偏特化进行讨论。


5.模板特化时的匹配规则
(1) 类模板的匹配规则
最优化的优于次特化的,即模板参数最精确匹配的具有最高的优先权
例子:
template <class T> class vector{//…//}; // (a)  普通型
template <class T> class vector<T*>{//…//};  // (b) 对指针类型特化
template <>   class vector <void*>{//…//};  // (c) 对void*进行特化
每个类型都可以用作普通型(a)的参数,但只有指针类型才能用作(b)的参数,而只有void*才能作为(c)的参数
(2) 函数模板的匹配规则
非模板函数具有最高的优先权。如果不存在匹配的非模板函数的话,那么最匹配的和最特化的函数具有高优先权
例子:
template <class T> void f(T);  // (d)
template <class T> void f(int, T, double); // (e)
template <class T> void f(T*);  // (f)
template <> void f<int> (int) ; // (g)
void f(double);  // (h)
bool b;
int i;
double d;
f(b); // 以 T = bool 调用 (d)
f(i,42,d) // 以 T = int 调用(e)
f(&i) ; // 以 T = int* 调用(f)
f(d);  //  调用(g)我怎么觉得是调用(h)
参考文献
[1] Bjarne Stroustrup, The C++ Programming Language (Special Edition), Addison Wesley,2000
[2] Nicolai M.Josuttis, The C++ Standard Library – A Tutorial and Reference ,Addison Wesley,1999
[3] Stanley Lippman and Josée Lajoie ,C++ Primier, 3rd Edition ,Addison Wesley Longman ,1998

 

转载自:http://blog.csdn.net/zhang810413/archive/2007/12/18/1948603.aspx

 

补充:

 

Partial Template Specialization能够让你在模板(Template)的所有可能的实体中特化出一组子集.
1.模板的特化(template specialization):
    例如,定义如下的一个模板:
    template<class Window, class Controller>
    class Widget
    {
      ... 泛化实现代码 ...
    };
    然后你可以像下面那样明确地加以特化:
    template<>    //注意:
template后面的尖括号中不带任何内容;
    class Widget<ModalDialog, MyController>
    {
      ... 特化实现代码 ...
    };
    其中ModalDialog和MyController是你自己另外定义的类;有了这个Widget的特化定义之后,如果你以后定义了Widget<ModalDialog, MyController>对象时,编译器就会使用上述的特化定义,如果定义了其它泛型对象,那么编译器就是用原本的泛化定义;这就是模板的特化.

2.Partial Template Specialization(模板偏特化)
    模板特化是通过"给模板中的所有模板参数一个具体的类"的方式来实现的.而模板偏特化则是通过"给模板中的部分模板参数以具体的类,而留下剩余的模板参数仍然使用原来的泛化定义"的方式来实现的;
    比如,就上面的Widget类模板的定义来说,有时候想针对任意的Window来搭配一个特定的MyController类特化Widget,这个时候就需要使用模板偏特化机制了.下面的Widget类模板就是Widget的偏特化定义:
    template<class Window>                        //仍然使用原来的泛化定义;
    class Widget<Window, MyController>            //MyController是具体的类,是特化定义;
    {
      ... 偏特化实现代码 ...
    };
    这就是一个偏特化定义;一个MyController类可以搭配任意一种Window.
    通常在一个类模板的偏特化定义中,你只会特化某些模板参数而留下其它泛化参数.当你在程序中具体实现上述类模板的时,编译器会试着找出最匹配的模板定义.这个寻找过程十分复杂精细,允许你以富有创意的方式来进行偏特化.例如,假设你有一个Button类模板,它有一个模板参数,那么,你不但可以拿任意的Window搭配特定的MyController来特化Widget,还可以拿任意Button搭配特定的MyController来偏特化Widget:
    template<class ButtonArg>
    class Widget<Button<ButtonArg>, MyController>    //使用任意Button搭配具体的类MyContorller
    {
      ... 偏特化实现代码 ...
    };
    模板的偏特化能力很强大.当你实例化一个模板时,编译器会把目前存在的偏特化模板和全特化模板做比较,并找出其中最合适、最匹配的实现.这样,灵活性就很大.但是不幸的是,模板的偏特化机制不能用在函数身上,不论成员函数还是非成员函数.

注意:
1.虽然你可以全特化类模板中的成员函数,但是你不能偏特化他们;
2.你不能偏特化命名空间级别(namespace-level)的函数(non-member).最接近"命名空间级别模板函数"的偏特化机制就是函数重载,那就意味着你对"函数参数"(而非返回值类型或内部所用类型)有很精致的特化能力;
3.特化或全特化时,template后面的尖括号中不带任何内容;

总结:
模板特化/全特化是指给每一个模板参数一个具体的类型,以具体实现这个模板,而且template后面的尖括号中不带任何内容;
模板偏特化是指只给部分模板参数一个具体的类型,来实现这个模板;

 

转载自:http://hi.baidu.com/klcdyx2008/blog/item/5adbf77b79f316f90bd1873c.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++——模板特化和偏特化 的相关文章

随机推荐

  • 深度学习总结(一)各种优化算法

    参考博文 码农王小呆 https blog csdn net manong wxd article details 78735439 深度学习最全优化方法总结 https blog csdn net u012759136 article d
  • 矢量vector之间用等号赋值的问题

    结论 可以 在程序上编个小程序试试就能知道了 vector v1 v1 pushback 2 v1 pushback 3 v1 pushback 4 vector v2 v1 cout lt lt v2 0 lt lt v2 1 lt lt
  • StringUtils 工具类 详细介绍

    https blog csdn net laukicn article details 69230022
  • Java 程序员,真的不能去外包吗?

    Java程序员是可以去外包的 外包公司通常会为客户提供技术服务 包括程序开发 系统维护和支持等 作为Java程序员 如果你有较强的Java技能 那么可以考虑去外包公司工作 在外包公司工作的优势包括 有机会去不同的客户处工作 能够更多地接触不
  • shell 脚本day4之 sed应用

    应用sed编写的点名器 root zabbix server day4 more name txt 李白 杜甫 白居易 孟浩然 苏轼 root zabbix server day4 more roll sh bin bash 功能描述 De
  • 用js实现滚动加载动画效果

    目录 一 效果图 二 代码部分 1 html结构 2 css样式部分 3 js部分 三 代码总结 一 效果图 可以看出 在悠方滚动条滚动的时候 当高度打到一定高度的时候就会出现一个div盒子 就好像刚加载出来一样 而且可以一直向下滚动 二
  • github 中使用 ssh

    从去年开始 github 对于 https 方式下载的仓库已经不支持直接 commit push 等操作 由于 https 方式简单快捷 对于大部分只是对 git 初步熟悉的用户来说是非常合适的 因为不需要做任何配置 只需要一个 githu
  • js之DOM0级和DOM2级绑定事件

    js原生注册事件分别为DOM0级 DOM2级 DOM0级事件 简单理解就是直接绑定 可以是直接在标签中绑定事件
  • LVGL笔记8--lv_style样式

    LVGL笔记8 lv style样式 样式是用来修饰UI美观性 使用lv style对UI界面进行重绘和重用 利用多个不同的样式来形成Theme对象 对于vl obj基础对象而言 每个对象都有一个lv style样式 但对于其他的控件 比如
  • 基于Java+SpringBoot+vue的社区报修维修平台(含源码和数据库)

    文章目录 简介 环境需要 住户前台功能模块 管理员功能模块 住户后台功能模块 维修员后台功能模块 简介 系统管理也都将通过计算机进行整体智能化操作 对于社区维修平台所牵扯的管理及数据保存都是非常多的 例如住户管理 社区公告管理 维修工管理
  • 目标检测笔记(十三): 使用YOLOv5-7.0版本对图像进行目标检测完整版(从自定义数据集到测试验证的完整流程))

    文章目录 一 目标检测介绍 二 YOLOv5介绍 2 1 和以往版本的区别 三 代码获取 3 1 视频代码介绍 四 环境搭建 五 数据集准备 5 1 数据集转换 5 2 数据集验证 六 模型训练 七 模型验证 八 模型测试 九 评价指标 一
  • Jupyter Notebook 添加代码自动补全功能

    自己记录以便后期参考与查询 转载参考 https www jianshu com p 0ab80f63af8a 安装 如果之前安装过显示目录功能的话 这一步骤可以跳过 pip install jupyter contrib nbextens
  • 【测试 2】二、软件质量与软件测试过程

    2 软件质量 2020年10月29日01 16 39 质量三要素 实体 特性 需求 软件质量6大特性 27个子特性 参考 https www cnblogs com jodyccf p 12200325 html 软件质量活动 保证软件质量
  • 认识RAID磁盘阵列

    认识RAID磁盘阵列 前几天在公司整理办公桌时找到了一份关于RAID的文档 对RAID介绍的很详细 这几天我利用空闲时间把这份文档录入到了电脑里 现分享给大家 认识RAID磁盘阵列 廉价冗磁盘阵列 Redundant Array of In
  • 运放使用总结篇(1) 运算放大器基本概念简介

    文章目录 前言 一 运算放大器是什么 二 运放的开环增益 三 运放的输入阻抗 输出阻抗 四 运算放大器的基本结构 五 运放的开环和闭环使用 总结 前言 作为硬件设计中最常用的运算放大器 有必要了解和掌握 单个三极管放大倍数离散度很大 虽然硬
  • IOS object-c基础

    第一讲 OC简介及基本语法 Objective C简称OC是在C语言的基础上 增加了一层最小的面向对象语法 完全兼容C语言 也就是可以在OC代码中混入C语言代码 甚至是C 代码 可以使用OC开发Mac OS X平台和IOS平台的应用程序 简
  • CAD动态块制作

    CAD动态块制作 拉伸动态块 柜体A拉伸动态块制作 第一步 制作柜体A 第二步 进入块编辑器编辑 第三步 关闭块编辑器 柜体B拉伸动态块制作 第一步 制作柜体B 第二步 进入块编辑器 第三步 关闭块编辑器 可见性动态块 第一步 找到动态块图
  • 计算机视觉基础之数字图像(2)

    目录 一 直方图 1 什么是直方图 2 直方图的性质 3 直方图均衡化 4 相关示例代码 二 滤波 1 定义 2 线性滤波 三 卷积 1 定义 2 卷积 过滤器 卷积核 Kernel 3 卷积的应用 4 卷积 步长 5 卷积 填充 一 直方
  • Web服务器如何确定哪个Servlet处理请求

    一 Web服务器 Web服务器概念较为广泛 我们最常说的Web服务器指的是网站服务器 它是建立在Internet之上并且驻留在某种计算机上的程序 Web服务器可以向Web客户端 如浏览器 提供文档或其他服务 只要是遵循HTTP协议而设计的网
  • C++——模板特化和偏特化

    1 引言C 中的模板分为类模板和函数模板 虽然它引进到C 标准中的时间不是很长 但是却得到了广泛的应用 这一点在STL中有着充分的体现 目前 STL在C 社区中得到了广泛的关注 应用和研究 理解和掌握模板是学习 应用和研究以及扩充STL的基