《产生式元编程》第五章 忆昔年模板三两事
前言 本系列分为上中下三个篇章,前四章作为上篇,详细介绍了宏在产生式编程中的原理和应用,本章开始步入中篇,正式进入 C++ 的产生式元编程技术。 宏是 C 时期的产物,功能颇为简陋,亦非图灵完备,即或诸般奇技妙诀加身,限制仍多。且调试不易,有所束缚,以是仅作辅助,用来实现简单的代码生成功能。至 C++ 时期,产生式元编程工具陡增,其中以模板为一切的根基,发枝散叶,尔今正向静态反射前进。 本章涉及不计其数的模板技术,主要集中于模板的核心理论和用法,概念错综复杂,技术层出不穷。难度等级绝对不低,是本系列中非常重要的一章。 纵然某些概念和技术你已知悉,也莫要跳过某个小节,因为本系列的重心不在模板编程,而在产生式编程,论述角度将有所差异。 泛型……元编程 传统过程式编程的思路是将逻辑作为函数,数据作为函数的输入和输出,通过无数个函数来组织完整的逻辑需求,好似搭积木,构建出各种物体。 面向对象编程更进一步,思路是将逻辑和数据合并起来,构成一个个类,类中包含各种数据和函数,外部只能借助公开函数操纵这些数据。这种以对象表示现实事物的方式与人的思维更加接近,简化了抽象化的难度。 泛型编程则欲将逻辑和数据分离,并提供一种抽象化数据的方式,使得不同的数据能够使用同一种逻辑,极大降低了代码的重复性。于是,同一个函数能够传递不同的参数类型,这叫函数模板;同一个类能够传递不同的数据,这叫类模板。 C++ 是一种多范式语言,以模板支持泛型编程,允许编写泛型的函数和数据,功能不依赖于某种具体的数据类型,使用 SFINAE 和 Concepts 约束抽象化的类型。这种能力使其支持 Parametric Polymorphism,在多态的选择上不必局限于传统的 Subtype Polymorphism,可以使用编译期多态替代运行期多态。 C++ 中,元编程指的是发生于编译期的编程,模板为 C++ 带来泛型编程的同时,也带来了元编程能力。由模板实现的元编程,称为模板元编程。而产生式元编程,指的是发生于编译期的对于编程的编程,模板本就支持在编译期生成代码,因此模板也能够实现产生式元编程。 抽象化、具体化……模板 在模板世界中,函数不再是具体的函数,数据类型也不再是具体的数据类型。模板宛如一个模具,借其能够产生各式各样的物体,这些物体的颜色、材料可能不尽相同,但是形状、大小是一致的。也就是说,一类物体,必须存在共同的部分,才能够抽象出一个模具,模具的作用就是重复利用这些共同之处,减少重复性。 编程是工具,本质是解决问题,解决问题考验的就是抽象化和具体化的能力。抽象化应对的是现实世界中的不变,而具体化应对的是现实世界中的变化,能够清楚地认识到变与不变是什么,问题也就迎刃而解了。那先来分清抽象化和具体化的概念。 抽象的意思是,在许多事物中,去除非本质的属性,抽出本质属性。抽象化就是呈现出具体事物共同本质的过程。将复杂的现实,简化成单纯的模型,这种抽象化方式称为模型化,所谓问题建模,就是对问题进行模型化,也即抽象的过程。具体的概念相对简单,就是指看得见摸得着的事物,每个事物都是独一无二的,是以变化尤盛。具体化就是将抽象事物加载清晰的过程,是一种有助于理解陌生事物的方式。数据类型是具体事物,能够清晰简明地呈现出不同数据类型的共同逻辑,就是用模板类型代替具体类型的精妙之处。 模板本身是一种抽象化的工具,以其编写的是抽象逻辑,表示某类类型的共有本质,是不变的部分。其本身是没有用的,实际需要的还是具体逻辑,因此需要有具体化的过程,将抽象逻辑转变为具体逻辑。在 C++ 模板中,这种将抽象逻辑转变成具体逻辑的过程,称为实例化。实例化将在编译期将抽象类型替换成具体类型,根据模板生成一个个具体逻辑。这种实例化机制,便是我们所需要的代码生成能力。 与宏不同,模板具体化后生成的代码,并无法直接在生成的源码中看到,但是可以通过 CppInsight 这类工具察看。 比如: template <typename T> inline constexpr T Integer = 42; int… Continue Reading 《产生式元编程》第五章 忆昔年模板三两事