C++ Template 模版的本质html
自动化是人类进化的动力程序员
AlexCoolweb
本文出现的目的,就是尽可能让人们理解C++模版设计的思想, 属于模板的心法。算法
我想知道上帝是如何创造这个世界的。我对这个或那个现象,这个或那个元素的能谱不感兴趣。我要知道的是他的思想。其余都是细节。express
——爱因斯坦编程
模版最初的目的就是为了减小重复代码,因此模版出现的目的就是为了解放C++程序员生产力。设计模式
content C++模版是什么 什么是参数化容器类 什么是通用算法 模板是怎么解决上面问题的 C++实现参数化类(class template)技术 C++实现模板函数(function template)技术 实现C++模板的几个核心技术 模版典型的应用场景有哪些 对模版的展望 更多细节请参考资料和进一步阅读
C++模版是什么?安全
程序 = 数据结构 + 算法数据结构
---Niklaus EmilWirth框架
最初C++是没有标准库的,任何一门语言的发展都须要标准库的支持,为了让C++更强大,Bjarne Stroustrup以为须要给C++提供一个标准库,但标准库设计须要一套统一机制来定义各类通用的容器(数据结构)和算法,而且能很好在一块儿配合,这就须要它们既要相对的独立,又要操做接口保持统一,并且可以很容易被别人使用(用到实际类中),同时又要保证开销尽可能小(性能要好)。 Bjarne Stroustrup 提议C++须要一种机制来解决这个问题,因此就催生了模板的产生,最后经标准委员会各路专家讨论和发展,就发展成现在的模版, C++ 第一个正式的标准也加入了模板。
C++模版是一种解决方案,初心是提供参数化容器类和通用的算法(函数)。
什么是参数化容器类?
首先C++是能够提供OOP(面向对象)范式编程的语言,因此支持类概念,类自己就是现实中一类事物的抽象,包括状态和对应的操做,打个比喻,大多数状况下咱们谈论汽车,并非指具体某辆汽车,而是某一类汽车(某个品牌),或者某一类车型的汽车。
因此咱们设计汽车这个类的时候,各个汽车品牌的汽车大致框架(骨架)都差很少,都是4个轮子一个方向盘,并且操做基本上都是相同的,不然学车都要根据不一样厂商汽车进行学习,因此咱们能够用一个类来描述汽车的行为:
class Car { public: Car(...); //other operations ... private: Tire m_tire[4]; Wheel m_wheel; //other attributes ... };
但这样设计扩展性不是很好,由于不一样的品牌的车,可能方向盘形状不同,轮胎外观不同等等。因此要描述这些不一样咱们可能就会根据不一样品牌去设计不一样的类,这样类就会变得不少,就会产生下面的问题:
1 代码冗余,会产生视觉复杂性,自己类似的东西比较多;
2 用户很难经过配置去实现一辆车设计,很差定制化一个汽车;
3 若是有其中一个属性有新的变化,就得实现一个新类,扩展代价太大。
这个时候,就但愿这个类是能够参数化的(属性参数化),能够根据不一样类型的参数进行属性配置,继而生成不一样的类。
类模板就应运而生了,类模板就是用来实现参数化的容器类。
什么是通用算法?
程序=数据结构+算法;
算法就是对容器的操做,对数据结构的操做,通常算法设计原则要知足KISS原则,功能尽可能单一,尽可能通用,才能更好和不一样容器配合,有些算法属于控制类算法(好比遍历),还须要和其余算法进行配合,因此须要解决函数参数通用性问题。举个例子:
之前咱们实现通用的排序函数多是这样:
void sort (void* first, void* last, Cmp cmp);
这样的设计有下面一些问题:
1.为了支持多种类型,须要采用void*参数,可是void*参数是一种类型不安全参数,在运行时候须要经过类型转换来访问数据。
2.由于编译器不知道数据类型,那些对void*指针进行偏移操做(算术操做)会很是危险(GNU支持),因此操做会特别当心,这个给实现增长了复杂度。
因此要知足通用(支持各类容器),设计复杂度低,效率高,类型安全的算法,模板函数就应运而生了,模板函数就是用来实现通用算法并知足上面要求。
模板是怎么解决上面问题的?
C++标准委员会采用一套相似函数式语言的语法来设计C++模板,并且设计成图灵完备 (Turing-complete)(详见参考),咱们能够把C++模板当作是一种新的语言,并且能够当作是函数式编程语言,只是设计依附在(借助于)C++其余基础语法上(类和函数)。
C++实现参数化类(class template)技术:
1.定义模板类,让每一个模板类拥有模板签名。
模板类语法:
template<typename T>
class X{...};
为何会存在这些分类,主要是知足不一样类对参数化的需求:
2.在用模板类声明变量的地方,把模板实参(Arguments)(类型)带入模板类,而后按照匹配规则进行匹配,选择最佳匹配模板.
3.选好模板类以后,编译器会进行模板类实例化--记带入实际参数的类型或者常量自动生成代码,而后再进行一般的编译。
C++实现模板函数(function template)技术:
模板函数实现技术和模板类形式上差很少:
template<typename T>
retType function_name(T t);
其中几个关键点:
实现C++模板的几个核心技术:
要理解这句话的关键点是failure和error在模板实例化中意义,模板实例化时候,编译器会用模板实参或者经过模板实参推导出参数类型带入可能的模板集(模板备选集合)中一个一个匹配,找到最优匹配的模板定义,
Failure:在模板集中,单个匹配失败;
Error: 在模板集中,全部的匹配失败;
因此单个匹配失败,不能报错误,只有全部的匹配都失败了才报错误。
2. 模板特化
模板特化为了支持模板类或者模板函数在特定的状况(指明模板的部分参数(偏特化)或者所有参数(彻底特化))下特殊实现和优化,而这个机制给与模板某些高阶功能提供了基础,好比模板的递归(提供递归终止条件实现),模板条件判断(提供true或者false 条件实现)等。
3. 模板实参推导
模板实参推导机制给与编译器能够经过实参去反推模板的形参,而后对模板进行实例化,具体推导规则见参考;
4. 模板计算
模板参数支持两大类计算:
5. 模板递归
模板递归是模板元编程的基础,也是C++11变参模板的基础。
模版典型的应用场景有哪些?
能够实现通用的容器(Containers)和算法(Algorithms),好比STL,Boost等,使用模板技术实现的迭代器(Iterators)和仿函数(Functors)能够很好让容器和算法能够自由搭配和更好的配合;
2 C++ type traits
经过模板技术,C++ type traits实现了一套操做类型特性的系统,C++是静态类型语言,因此须要再编译时候对类型进行检查,这个时候type traits能够提供更多类型信息给编译器,能让程序能够作出更多选择和优化。 C++创始人对traits的理解:
”Think of a trait as a small object whose main purpose is to carry information used by another object or algorithm to determine "policy" or "implementation details". - Bjarne Stroustrup
3. Template metaprogramming-TMP
随着模板技术的发展,模板元编程逐渐被人们发掘出来,metaprogramming本意是进行源代码生成的编程(代码生成器),同时也是对编程自己的一种更高级的抽象,比如咱们元认知这些概念,就是对学习自己更高级的抽象。 TMP经过模板实现一套“新的语言”(条件,递归,初始化,变量等),因为模板是图灵完备,理论上能够实现任何可计算编程,把原本在运行期实现部分功能能够移到编译期实现,节省运行时开销,好比进行循环展开,量纲分析等。
(取自参考文献6)
4. Policy-Based Class Design
C++ Policy class design 首见于 Andrei Alexandrescu 出版的 《Modern C++ Design》 一书以及他在C/C++ Users Journal杂志专栏 Generic<Programming>,参考wiki。经过把不一样策略设计成独立的类,而后经过模板参数对主类进行配置,一般policy-base class design采用继承方式去实现,这要求每一个策略在设计的时候要相互独立正交。STL还结合CRTP (Curiously recurring template pattern)等模板技术,实现相似动态多态(虚函数)的静态多态,减小运行开销。
5. Generic Programming
因为模板这种对类型强有力的抽象能力,能让容器和算法更加通用,这一系列的编程手法,慢慢引伸出一种新的编程范式:泛型编程。 泛型编程是对类型的抽象接口进行编程,STL库就是泛型编程经典范例。
对模版的展望
模板的代码和一般的代码比起来,可读性不好,因此很难维护,对人员要求很是高,开发和调试比较麻烦。 对模板代码,实际上很难覆盖全部的测试,因此为了保证代码的健壮性,须要大量高质量的测试,各个平台(编译器)支持力度不同,可移植性不能彻底保证。模板颇有可能会隐式地增长二进制文件的大小,多个实例等,因此模板在某些状况下有必定代价;
2. 基于模板的设计模式
随着C++模板技术的发展,以及大量的经验总结,逐渐造成了一些基于模板的经典设计,好比STL里面的特性(traits),策略(policy),标签(tag)等技法;Andrei Alexandrescu 提出的Policy-Based Class Design;以及Jim Coplien的curiously recurring template pattern (CRTP),以及衍生Mixin技法;或许将来,基于模板能够衍生更多的设计模式。
3. 模板的将来
C++标准准备引进Concepts(Concepts: The Future of Generic Programming by Bjarne Stroustrup)解决模板调试问题,对模板接口进行约束;随着模板衍生出来的泛型编程,模板元编程,模板函数式编程等理念的发展,未来也许会发展出更抽象,更通用编程理念。模板自己是图灵完备的,因此能够结合C++其余特性:编译期常量和常量表达式,编译期计算,继承,友元friend等开阔出更多优雅的设计,好比元容器,类型擦除,自省和反射等,未来会出现更多设计。
但愿本文对想学习C++模板的同窗有必定的帮助,有不对的地方还请指正,多谢!
更多细节请参考资料和进一步阅读:
1《The design and Evolution of C++ 》Bjarne Stroustrup;
2. C++ Templates are Turing Complete,Todd L. Veldhuizen,2003(做者网站已经停了,archive.org 保存的版本,archive.org 可能被限制浏览);
3. 模板细节:
wikipedia.org, cppreference.com(C++,模板template, Template metaprogramming, CRTP (Curiously recurring template pattern), Substitution failure is not an error (SFINAE), template_argument_deduction ,Policy-based_class design, Expression templates,等);
C++ Programming/Templates/Template Meta-Programming
4.模板的基本语法:
C++标准ISO+IEC+14882-1998,2003,2011;
《C++ Templates: The Complete Guide》 by David Vandevoorde, Nicolai M. Josuttis;
5.模板设计进价:
Andrei Alexandrescu 的 《Modern C++ Design》;
候捷的《STL源码剖析》;
More C++ Idioms:wikipedia.org
6. 模板元编程:
Abrahams, David; Gurtovoy, Aleksey. C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond. Addison-Wesley. ISBN 0-321-22725-5.
Metaprogramming in C++,Johannes Koskinen,2004
7.Blog and papers:
Coplien, James O. (February 1995). "Curiously Recurring Template Patterns" (PDF). C++ Report: 24–27.
https://en.wikipedia.org/wiki/Mixin