文档章节

篮子、水果和鸡蛋——关于C++的模板偏特化和萃取编程技法

costaxu
 costaxu
发布于 2012/12/22 23:19
字数 1291
阅读 1759
收藏 31

最近在读《STL源码剖析》。读这本书的时候发现自己的C++的知识其实是非常匮乏的。 从大学的C++教材上学到一些C++基本的语法、内存管理、继承、多态等方面的基础知识。这些只是是一棵大树的根。而读STL的源码和侯捷的解析的时候,发现C++还有很多丰富的细节和技巧。这些是大树上的枝叶。学习C++,不仅要学习根,也要学习枝叶,这样才能让大树茂盛起来。虽然C++语法一些用法较为晦涩,但读完这些代码之后觉得思路比以前更开阔,另外可以活动脑筋。

比如模板的偏特化这个特性。侯捷的《STL源码剖析》中对于模板的偏特化(partial specialization)的解释为: 如果class template拥有一个以上的template参数,我们可以针对其中某个或多个 template参数进行特化工作。template是一个很抽象的东西。template偏特化之后就让模板变得具体那么一点点。

用一个形象一点的比喻吧。我们把template比作一个装东西的篮子。这个篮子既可以装鸡蛋,也可以装苹果。那么所谓偏特化就是让你用一个篮子专门装水果,这就是template水果篮。以后你就只能使用水果篮来装苹果、装梨,而不能使用其他的篮子来装这些水果了。

看一个STL例子:

有一个“篮子” iterator_traits, 它内部typedef 了value_type类型,用来定义模板的参数类型class I 的value_type。

template<class I>
struct iterator_traits
{
    typedef typename I::value_type value_type;
};
如果用一般的STL的iterator类型去实例化这个模板的时候是不会有问题的,因为STL内建的iterator里typedef了value_type。但是如果用原生指针去实例化这个模板就悲剧了。因为原生指针可没有办法typedef什么东西。如果把iterator比作鸡蛋,把原生指针比作水果,那么这个篮子就只能装鸡蛋而不能装水果。如果必须要装水果,怎么办?


办法就是用模板的偏特化,给水果专门做一个水果篮了。看下面的代码

template <class T>
struct iterator_traits<T*>
{
typedef T value_type;
}

当用原生指针T*去实例化iterator_traits模板的时候,就会调用上面的代码把类型T typedef为value_type。这就相当于给iterator_traits实现了一个特别的版本专门处理原生指针。也就是说,水果篮做好了:)

如果理解了模板的偏特化, 就理解了萃取编程技法的一大半了。什么是萃取编程技法呢? 萃取来自于英语的traits, traits的意思是特性、特点。萃取编程技法实际上就是利用模板的偏特化,充分的萃取不同型别的特点。

还是拿鸡蛋、水果和篮子做例子。别看装鸡蛋、水果都用篮子,但是装鸡蛋的篮子和装水果的篮子能一样吗? 装鸡蛋的篮子一定要抗摔防震。因为鸡蛋壳很脆一碰就破。而装水果的篮子则要美观好看。因为水果篮一般都用作送给别人的礼物。

还是用上面的iterator_traits 这个篮子做例子,看下面的代码。

template<class I>
struct iterator_traits
{
    typedef typename I::value_type value_type;
}; //泛化版本

template<class I>
struct iterator_traits<T*>
{
    typedef T value_type;
}; //偏特化版本

我们给这个iterator_traits设计了两个版本。上面的是泛化的版本,下面的是为原生指针偏特化的版本。

如何使用iterator_traits这个篮子呢,看下面这个模板函数:

template <class I>
typename iterator_traits<I>::value_type 
func(I ite)
{
    return *ite;
}

这个模板函数以一个class I作为类型参数, 函数的参数为一个class I类型的对象, 返回的是class I对象提领的对象。函数的返回值类型定义就使用了萃取编程的技法。我们看函数返回值的定义:

iterator_traits<I>

这个模板就是上文中我们定义的篮子。在上文中我们针对不同类型的特点,实现了两种将template的实例化的方法:实现了用STL的iterator去实例化这个模板的方法,也实现了用原生指针去实例化这个模板的方法。因为我们“因材施教”的调用了不同的代码,才把水果放在了水果篮里,把鸡蛋放在其他的篮子里。这就是萃取的编程技法。


C++的语法是很艰深的。STL对于C++的使用也可以说是很有“创造性”。 因为这种“创造性”,给我们阅读STL源码的时候造成了一定的困难,不过也是因为这种“创造性” , 让我们使用STL的时候非常的轻松和愉快。哎,这就是所谓的“痛并且快乐着”的那种感觉吧。





© 著作权归作者所有

共有 人打赏支持
costaxu

costaxu

粉丝 147
博文 56
码字总数 86451
作品 0
深圳
程序员
私信 提问
c++ 模板之特化

特化  何为特化,特化也是我们指定一些类型,当我们传入响应的类型的时候,模板生成的类是我们指定类型所对应的类。  可能有的时候我们有这样的需求,普通参数我们走平常的模板类,而对于个...

sdoyuxuan
2018/01/25
0
0
STL — 迭代器设计思维(一)

迭代器设计思维 关于迭代器的基础原理和作用我以前有一个博客提到过:STL迭代器的原理以及迭代器失效 我不推荐不够了解迭代器的读者直接来看这个博客,因为你 会觉得我在做一些无意义的事情,...

Dawn_sf
2017/12/19
0
0
C++ 模板惯用法

原文:C++ 模板惯用法 作者:Breaker 关于 C++ 模板编程的惯用法,note-to-self + keynote + idiom case + cross-reference 式笔记 目录 模板语法 模板惯用法示例 堆栈上分配 编译优化的开关...

晨曦之光
2012/05/23
1K
0
STL中实现 iterator trail 的编程技巧

STL中实现 iterator trail 的编程技巧 《泛型编程和 STL》笔记及思考。 这篇文章主要记录在 STL 中迭代器设计过程中出现的编程技巧,围绕的 STL 主题为 (迭代器特征) Iterator traits 和 ...

何必诗债换酒钱
2018/07/18
0
0
从 C++98 到 C++17,元编程是如何演进的? | 技术头条

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/csdnnews/article/details/86297148 作者 | 祁宇 责编 | 郭芮 出品 | CSDN(ID:CSDNnews) 不断出现的C++新的...

CSDN资讯
01/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

ehcache

简单介绍 EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。Ehcache是一种广泛使用的开 源Java分布式缓存。主要面向通用缓存,Java EE和轻量...

大笨象会跳舞吧
9分钟前
0
0
Android服务2 BindService

MainActivity { class MyService extends Service { public void onCreate() {} public IBinder onBind(Intent intent) { //return new Binder(); retutn new MyBinder(); } public boolean ......

Coding缘
48分钟前
0
0
所有和Java中代理有关的知识点都汇集于此,速进学干货。

对于每一个Java开发来说,代理这个词或多或少都会听说过。你可能听到过的有代理模式、动态代理、反向代理等。那么,到底什么是代理,这么多代理又有什么区别呢。本文就来简要分析一下。 代理...

Java填坑路
54分钟前
1
0
镜像即代码:基于Packer构建阿里云镜像

什么是Packer Packer是HashiCorp推出的一款工具,旨在提供简易的方式自动化构建镜像。通过Packer,你只需要在配置文件中指明镜像构建所需的基本信息及期望安装到镜像中的软件及配置,即可通过...

迷你芊宝宝
55分钟前
1
0
好程序员前端教程之JavaScript闭包和匿名函数的关系详解

好程序员前端教程之JavaScript闭包和匿名函数的关系详解 本文讲的是关于JavaScript闭包和匿名函数两者之间的关系,从匿名函数概念到立即执行函数,最后到闭包。下面一起来看看文章分析,希望...

好程序员IT
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部