panda ID:pandaxcl
79164次访问,排名1150(1)好友0人,关注者2
pandaxcl的文章
原创 61 篇
翻译 0 篇
转载 0 篇
评论 151 篇
pandaxcl的公告

博客文档资源下载在本人的网站下载!!!

我也优先在我的网站论坛上面回答问题

在研究C++自动化编程好久之后,发现C++自动化编程在国内还是一个空白。所谓的C++自动化编程,简单点说就是采用了C++的高级模板技术配合产生式编程技法实现了C++代码的自我配置,自动维护代码之间的种种一致性问题。关于这个问题的讨论,将会在我的网站上面进行细致的讨论。如果有问题,欢迎来我的网站提问哦。看看下面的我的网站的链接。

EMail:pandaxcl@163.com

QQ:56637059

我的网站: http://www.autodev.net

最近评论
huxi043715:博主,在很强阿。你的文章也很容易懂。
wangwei200508:呵呵,谢了
您的这里指到自己硬盘了
<a href="file:///D:/work/lex_yacc/chapter01/lexyacc.rar.png" target="_top">这里</a>
imath:老大我引用了你的 这系列文章,嘿嘿
dlr0987:abc* = ab (c+|e) =ab|abc|abcc.....

pandaxcl:这里要注意那个return i
前置和后置都是为了实现增一的效果;)
特意实现前置和后置都是相同的功能的;)
文章分类
收藏
    相册
    友情连接
    小熊猫
    我的另外一个博客
    我的网站-自动化编程社区
    我的论坛-自动化编程社区论坛
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 自动化C++程序设计---C++里的模板语言收藏

    新一篇: 自动化C++程序设计---分析C++类层次 | 旧一篇: 应用篇_撤销(Undo)和重做(Redo)的C++自动化实现(6)---扩展的框架代码

    书名: 《自动化C++程序设计》
    作者: 熊春雷
    网站: http://www.autodev.net
    Blog: http://blog.csdn.net/pandaxcl
    EMail: pandaxcl@163.com
    昵称: pandaxcl,开心
    QQ: 56637059
    MSN: pandaxcl@163.com
    版本: 0.01 于2007/09/25
    目标: 所有C++爱好者
    版权: 本文的版权归熊春雷所有
    代码库: autocxx(在论坛下载

    Warning

    1. 本文由熊春雷所写,绝对保证原创,在此特别严肃声明。本人简介:熊春 雷,男,1980年出生于湖北钟祥;七岁随父迁往宜昌开始学生生涯,小学和初中在 湖北宜昌樟村坪镇职工子弟学校就读;1996年考上宜昌县高中,开始三年的高中生 活;1999-2003就读于湖北大学物理系;2003-2006就读于武汉大学物理系。现就职 于盛大网络:)

    2. 绝对不能容忍他人说本文为他所写以及其他的侵权行为。一旦发现,一定 尽本人最大的能力以法律的形式严追到底,决不妥协。

    3. 引用本文,要保证本文的完整性,不可以删除此处的声明,并且务必注明出处。

    Tip

    1. 本文编写的所有代码可以用于任何用途(包括商业用途)。

    2. 用于商业用途的需要在最后发布的软件中声明借鉴了本文的思想。具体事 宜可以协商解决,(代码决不收取任何费用)。

    3. 其他事项可以和我联系,包括技术讨论等等:)或者直接登陆网站论坛: http://www.autodev.net

    Note

    1. 本文受到了《C++设计新思维》和《产生式编程》两本书的影响,同时也查阅了大 量的资料,从Loki库和Boost库中也吸收了不少营养,特此感谢之。

    2. 本文由于处于原创阶段,难免会出现各种各样的错误。代码出现错误的可能性非常 小(本来想说为零的),因为文档和代码是严格同步的,这是由VST文本的include 所保证的,代码都是测试成功之后才发布的。

    3. 本文所编写的代码,经过了VC2005编译器和g++编译器的测试,并且都通过了。

    4. 本文还没有彻底完成,算是一个初级版本,未来还将继续完善。暂时发布出来是为 了预知读者群有多少,读者越多,我的成就感越强,写作的时候也会更有动力:)

    5. 本文还会继续完善,欢迎各位读者的批评指正,也接受各种各样的建议,在权衡之 后以决定是否加入本书。

    6. 本书还没有最终完成,还会不断的进行完善,更新之后的内容将会发表于我的 网站我的博客。所以还需要读者多多关心本文的进展:)

    Contents

    C++里的模板语言

    静态诊断

    在本文中会大量的应用C++模版的 静态行为 ,也就是验证模版运算是否确实发生在编 译器编译源代码的时候。为了证明模版是运行在编译期,首先就必须给出一个可以判断是 否在编译期运行的检测机制。实际上,任何能够静态传入整型参数的编译错误都可以作为 静态断言的实现机制。

    Tip

    • 编译器编译C++代码的时候,C++代码执行的运算,这就是 静态运算

    • 编译器编译完C++代码之后就产生了可执行文件,运行该可执行文件就可以执行运

    • 算,这就是 动态运算

    下面看看C++中有多少种可以利用的这种编译错误:

    • 定义数组的时候,数组元素数量为零

    • 定义类对象的时候,该类有纯虚函数

    首先来看看 定义数组的时候,数组元素数量为零 的情况:

     char CompileError[1==2];//在这里就会有一个编译期的错误提示  char CompileOK[1!=2];//在这里就不会有编译期的错误提示   #define STATIC_ASSERT(expr) {char CompileError[expr];}  STATIC_ASSERT(1==2);//引发编译器错误  STATIC_ASSERT(1!=2);//编译顺利通过   #define STATIC_ASSERT_MSG(expr,msg) {char CompileError##msg[expr];}  STATIC_ASSERT_MSG(1==2,_1_must_equal_2);//引发编译器错误,并给出提示  STATIC_ASSERT_MSG(1!=2,_1_must_not_equal_2);//编译顺利通过,不给出提示  

    但是从上面的情况看来,还是需要利用宏来实现编译期诊断。一旦使用了宏,那么这个 STATIC_ASSERT 和STATIC_ASSERT_MSG就不能够被放到C++的名字空间(namespace)里面,这 一 点在C++中是应该尽力避免的。下面再来看看不使用宏的情况,也就是定义类对象的时 候, 该类有纯虚函数的情况:

     template<bool>struct static_assert// 这里模版参数为true是通用情况  {  };  template<>struct static_assert<false>// 针对模版参数为false进行特化  {      virtual void COMPILE_ERROR()=0;  };  

    由于static_assert是模版而不是宏,因此就可以将static_assert放到C++的名字空间 (namespace)中,这样 就避免了污染全局名字空间。下面来看看这里的static_assert的使 用情况:

     static_assert<1==1>();// 不引起编译期错误  //static_assert<1==2>();// 将引起编译期错误  

    有了上面的静态诊断函数之后,我们就可以利用static_assert来实现静态断言了:)但是 在书写测试代码的时候,更加常用的静态诊断是下面的两个模版:

     // 断言两个类型是否是同类型的静态诊断函数  template<class T1,class T2>struct static_assert_same// 一般情况就是一个抽象类  {      virtual void COMPILE_static_assert_same_ERROR()=0;// 纯虚函数  };  template<class T1>struct static_assert_same<T1,T1>// 针对相同类型参数进行特化  {// 没有纯虚函数,所有声明变量的时候就不会产生编译器错误  };   // 断言两个类型是否不是同类型的静态诊断函数  template<class T1,class T2>struct static_assert_not_same// 一般情况就是一个普通类  {// 没有纯虚函数,所有声明变量的时候就不会产生编译器错误  };  template<class T1>struct static_assert_not_same<T1,T1>// 针对相同类型参数进行特化  {      virtual void COMPILE_static_assert_not_same_ERROR()=0;// 纯虚函数  };  

    下面就是上面的两种静态诊断的使用实例:

     static_assert_same<int,int>();  //static_assert_same<int,float>();// 将引起编译错误   static_assert_not_same<int,float>();  //static_assert_not_same<int,int>();// 将引起编译错误  

    为什么说模版是C++的子语言

    使用过C++的人都或多或少的使用过C++模版技术,有可能你还没有觉察到:)例如,只要是 C++的使用者 都使用过C++流,实际上比较新的C++流库都是采用的模版实现:)另外STL作为 C++标准库就是模版应用 最典型的实例之一。除此之外还有大量的C++模版库:Boost, Loki,blitz++等等。

    模版作为C++的另外一个语言嵌入在C++语言里面,相对于普通的C++代码运行在运行期,模 版语言是运 行在编译期(编译器编译源代码的时期)的。

    为了证明模版是C++的子语言,那么首先就必须弄明白什么是计算机语言, 不过在这里不 会进行详细的理论证明,那是计算机科学家的事情。为了简单,我在这里给出一个 计算机 语言的简单命题:

    满足下列所有条件的就是计算机语言:

    • 可以执行运算(包括数值运算和符号运算)

    • 拥有选择结构

    • 拥有循环结构

    常见的计算机语言,例如:C/C++ BASIC PASCAL FORTRAN 等均满足上面的三个条件。

    静态数学运算

    下面是最简单的模版代码(如果看不懂,可以参看介绍C++模版的书籍C++ Template 书籍 ):

     template<int a,int b>struct Add  {      enum{value=a+b};// 整数加法  };  template<int a,int b>struct Sub  {      enum{value=a-b};// 整数减法  };  template<int a,int b>struct Mul  {      enum{value=a*b};// 整数乘法  };  template<int a,int b>struct Div  {      enum{value=a/b};// 整数除法  };  template<int a,int b>struct Mod  {      enum{value=a%b};// 整数求余  };  

    下面就是上面的静态加法的使用例子:

     static_assert<Add<2,1>::value == 3>();  static_assert<Sub<2,1>::value == 1>();  static_assert<Mul<2,2>::value == 4>();  static_assert<Div<4,2>::value == 2>();  static_assert<Mod<4,2>::value == 0>();  

    从上面的整数运算可以看出:运算的对象仅限于整数,但是这并不是什么限制,有了整数 的 运算之后,就可以很容易的实现实数的各种运算!另外还需要注意的是:运算的结果保 存在枚举 量中。这一点和运行期运算不同,编译期的运算结果只能保存在枚举值中(我还 没有发现其它的 可以保存静态数学运算的地方:))!总结起来就是下面两条:

    • 运算的对象仅限于整数(int char short long bool)

    • 编译期的整数运算结果保存在枚举值中(value)

    静态选择结构

    有了上面的基本数学运算之后,再来看看静态的选择结构:

     template<int>struct on// 通用模版A  {      enum{value = -1};  };  template<>struct on<2>// 针对于2的特化版本  {      enum{value = +9};  };  template<>struct on<1>// 针对于1的特化版本  {      enum{value = +8};  };  template<>struct on<0>// 针对于0的特化版本  {      enum{value = +7};  };  

    从上面的on模版可以看出,使用了C++的模版特化(这里使用的是模版完全特化)。

    下面的代码就是上面的on选择结构的测试用例:

     static_assert<on<0>::value == +7>();// 选择特化模版0  static_assert<on<1>::value == +8>();// 选择特化模版1  static_assert<on<2>::value == +9>();// 选择特化模版2  static_assert<on<3>::value == -1>();// 选择通用模版A  static_assert<on<4>::value == -1>();// 选择通用模版A  static_assert<on<9>::value == -1>();// 选择通用模版A  

    从上面的on模版可以看出,模版的选择结构完全依靠C++的模版(偏)特化 机制实现的。

    Tip

    • 所谓的 模版完全特化模版偏特化 ,他们之间的区别体现在模版参数的

    • 特别化是否是 全部 上面:

    • 如果所有的模版参数全部被特别化了就是 模版完全特化 ,或者 模版特化

    • 只有一部分参数被特别化,则被称为者 模版部分特化模版偏特化

    前面的on模版只有一个模版参数, 所以针对于2,1,0的int参数特化采用了 **完全 特化**;如果模版参数不止一个,那么就会出 现只特别化一部分参数的情况。 除了 上面的比较形式化的选择结构之外,对于整型还可以有?:选择 结构,它也是运行在编 译期的:

     static_assert<1==2?false:true>();// 不会引起编译错误  static_assert<1==1?false:true>();// 将会引起编译错误  

    静态循环结构

    在谈论静态循环结构之前,首先来看看计算1+2+3+...+100的数列求和问题:

     int Sum(int i)  {      if(0==i)return 0;// 递归终止条件      return i+Sum(i-1);// 进行递归处理  }   // 计算数列之和:1+2+3+...+100  assert((Sum(100)==5050));// 在程序的运行期执行  

    上面的1+2+3+...+100的数列求和采用了程序设计中经常采用的递归 方法,这也是我们将 要讨论的静态C++程序设计的关键技术。

    从上面递归实现的1+2+3+...+100的数列求和问题可以看出递归得以实现所必须满足的条件 :

    • 必须要有终止条件,否则就会出现无限递归

    • 递归过程可以自己调用自己,例如Sum函数体内又调用了Sum函数

    有了上面的递归条件,我们再来看看静态C++代码如何通过模版来实现递归:

     template<int i>struct Sum  {      enum{value=i+Sum<i-1>::value};// 自己调用自己  };  template<>struct Sum<0>// 终止条件,这里还有一个选择结构  {      enum{value=0};  };   // 计算数列之和:1+2+3+...+100  static_assert<Sum<100>::value==5050>();// 在编译期执行  

    从上面的静态循环可以看出:采用模版递归就可以实现静态循环结构。但是我们知道采用 递归方式可以实现任意形式(for while do-while)的循环结构,所以静态循环也就可以完 全实现了。

    运算结果的保存

    从前面的几节可以看出:我们操作的对象都是 整数 ,运算的结果也是 整数 , 但是在静态模版编程中还会大量使用 类型 作为操作对象,运算的结果也是 类型 。那么就有必要对这里的 操作对象运算结果 进行总结,同时为了使后面的 编码比较方便,必须对这里的 操作对象运算结果 进行统一!

    可以想象,如果在处理的过程中只有一种 操作对象 并且也只有一种 运算结果 ,那么编码就会得到极大的简化:-)

    有了这种想法之后,就存在两种方案:

    • 将类型统一到整数

    • 将整数统一到类型

    很显然,第二种方案实现比较容易,因此也就出现了下面的将整数统一到类型的模版类 n

     template<int i>struct n  {      enum{value = i};// 整数值保存于此  };  

    有了这里的模版类 n 之后就可以将前面的整数运算结果保存到这里的模版类 n 中:

     template<class A0,class A1>struct add// 静态整数加法  {      typedef n<A0::value+A1::value> type;  };   static_assert_same<n<3>,add<n<1>,n<2> >::type>();  static_assert_not_same<n<4>,add<n<1>,n<2> >::type>();  

    可以看出,对于整数操作的对象和结果都可以象对待类型一样来操作,因此在后面的编码过程 中,都将采用这里的方法来处理整数:-)

    有了上面的模板n之后,就可以将前面的静态数学运算规范化了!规范化列表如下:

     template<class A0,class A1>struct add// 静态整数加法  {      typedef n<A0::value+A1::value> type;  };   template<class A0,class A1>struct sub// 静态整数减法  {      typedef n<A0::value-A1::value> type;  };   template<class A0,class A1>struct mul// 静态整数乘法  {      typedef n<A0::value*A1::value> type;  };   template<class A0,class A1>struct div// 静态整数除法  {      typedef n<A0::value/A1::value> type;  };   template<class A0>struct inc// 静态整数増一  {      typedef n<A0::value+1> type;  };   template<class A0>struct dec// 静态整数减一  {      typedef n<A0::value-1> type;  };  

    下面是上面的基本运算的测试用例:

     static_assert_same<n<5>,add<n<3>,n<2> >::type>();// 5 == 3+2  static_assert_same<n<1>,sub<n<3>,n<2> >::type>();// 1 == 3-2  static_assert_same<n<6>,mul<n<3>,n<2> >::type>();// 6 == 3*2  static_assert_same<n<1>,div<n<3>,n<2> >::type>();// 1 == 3/2  static_assert_same<n<4>,inc<n<3> >::type>();// 4 == 3+1  static_assert_same<n<2>,dec<n<3> >::type>();// 2 == 3-1  

    上面的这些规范化的代码将会在后面的代码中用到,是autocxx库的组成部分:)

    发表于 @ 2007年10月23日 21:42:00|评论(loading...)|编辑

    新一篇: 自动化C++程序设计---分析C++类层次 | 旧一篇: 应用篇_撤销(Undo)和重做(Redo)的C++自动化实现(6)---扩展的框架代码

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © pandaxcl