winston 发表于 2007-12-29 17:34:10

关于“元编程”的浅思考

前几天看了荣耀的《C++模板元编程技术与应用》演讲,提到了元编程的一些好处和不利。
转自:http://blog.vckbase.com/zhangjw_cn/archive/2006/02/16/17772.html

    由于模板具备展开的特性,特化提供了选择的能力,因此很容易得到以下好处:
    1. 编译期计算
      比如我们计算Fibonacci数列,就可以避免以往的运行期计算,直接在编译期由编译器计算出需要的结果。
    2. 编译期选择
      作者给出了通过条件选择两个模板类型之一的示例。

    并能在以下方面取得较好的应用前景
    1. 编译期结构控制
      因为具备了特化选择的能力,很容易实现编译期的if流程;加上模板展开能力,将非常容易的做到for等的循环开解;条件的选择,同样相当方便的就做到了switch。
    2. 编译期数据结构
      数据的存储,同样可以通过特化能力进行分支选择。
    3. 数值计算
    4. 类型计算
    5. 代码生成
    6. 编译期断言和约束
      通过不存在的展开代码和条件,导致编译无法通过,从而实现断言。
    7. 库设计
    8. DSEL(domain-specific embedded language)设计

    模板元编程的不利:
    1. 代码的可读性较差
    2. 调试困难
    3. 编译时间延长
    4. 结果程序性能未必一定最优化
    5. 编译器局限性
    6. 可移植性较差

    作者准确、严格、精确的描述,给我们指出了一片广阔的空间。C++本身就是一个程序员负责的语言,程序员的稍有大意,就会造成无法预期的结果。我们生成的代码,编写的程序、软件,本身就是交给机器去运行的,不管是直接在硬件上执行,还是在VM上运行。元编程无疑是将部分代码交给了编译器去解释执行。
   1. 编译期计算真的那么重要?
      拿作者给出的Fibonacci数列,编译器的解释,为什么不能在运行期获得,而直接赋值呢?一个是编译器先解释,一个是另一个程序先运算。通常我们垢弊的就是直接赋值可读性差,元编程天生的毛病这里也有。当我们对所赋值有着提示性的注释时,结果并全然不一样了。
    2. 编译期选择真的那么重要?
      这一技巧性的特化所得到的结果最终是固定的代码,直接也可以写出我们需求的这个固定的代码。一个是我们编写给机器生成的代码(我们间接编写),一个是我们直接编写的代码。

    对应更具体的应用,带给了我们什么?
    1. 编译期结构控制
      结构流程的控制,本来是我们控制程序运行的。编译器的流程控制:If选择流程,除了一层奇怪的包装,并没有带来更清晰的流程,更高的效率;开解的循环,同样对运行期无能为例,对编译时本身就固定的循环,只是比手动的开解书写的更快,但却带来了奇怪的语法;switch跟是奇怪的语法。它们带来的,究竟是什么?除了新的奇怪的语法(其实也不新了,从模板的引入,这种语法就已经诡异的出现在了我们面前),恐怕更难有明显的好处。
    2. 编译期数据结构
      把本来就复杂的结构,变得更扑朔迷离,诡异难辨。
    3. 数值计算
      元编程对数值的计算,主要体现在编译器的展开解释上,预计算的元代码改为运行期代码,最终需要的结果也一样。同样是编程,编写运行期的这段代码,由于已有的经验和较少的技巧,大多数人可以更快的编写;对元程序需要的编译时间,运行期的编译显得更少,多的只是新建工程的时间;对于C++标准要求的至少12次迭代能力,运行期显得更为宽松自由。
    4. 类型计算
      数据类型通常是程序员手动编写的,对程序员而言并不需要判断,尤其是C++这种由程序员负责的语言。
    5. 代码生成
      在遇到大量类同相似的代码时,为了减少编码时间,我通常采用宏生成代码。同样的调试困难,但清晰的宏将使得你一看便知。对于采用编译期分支、展开能力生成代码,可读性不佳并难以调试,我更倾向于手动去编写这部分代码。
    6. 编译期断言和约束
      采用特化的技巧,使得编译时失败,面对编译器里输出的那一堆信息,通常要查找上半天,才能知道问题所在。对于C/C++程序员,我们会确保表达式求值的正确。去编写一个static_assert,并没有习惯了自身确保表达式求值正确,更快捷,效果可能也不太那么明显。当然,当编译器提供了这一支持时,对我们来说,也可带来适度的便利。
    7. 库设计
      在C++,已经漫天飞舞着template的今天,库设计,可能是元编程带来的好处可以被极大发挥和应用的地方。
    8. DSEL设计
      采用C宏编写脚步的例子以前也曾见过。

    由于以上的优点和缺点,而这些优点在通常编程中并不明显,估计也就是今天我们看到的元编程的现状结果。

    附:我见过一个元编程实现的max函数,不过,相对于宏,我委实没有发现它的好处所在。

wishel 发表于 2009-7-10 15:27:49

模板元编程非常可怕,据说已经被证明是图灵完备的。它的计算不是通过运行编译出来的程序,而是由编译器来完成,一旦编译完成,结果也就出来了。
个人看法这不适合普通项目,可读性可维护性差。但很适合开发库,因为有性能优势。且库的开发这一般都比较牛,可读性和维护性问题也不大。具体实现虽然难懂,但只要接口清晰就能方便用户使用。

guitar1314 发表于 2010-3-30 16:48:00

挺深奥的新技术啊,没看懂。
页: [1]
查看完整版本: 关于“元编程”的浅思考