??xml version="1.0" encoding="utf-8" standalone="yes"?>少妇人妻88久久中文字幕,国产日韩久久久精品影院首页
,久久人人爽人人爽人人AV东京热 http://m.shnenglu.com/shifan3/category/3013.htmlEverything is template... zh-cn Tue, 20 May 2008 22:42:04 GMT Tue, 20 May 2008 22:42:04 GMT 60 意不是凡h能领会的Q?Q?/title> http://m.shnenglu.com/shifan3/archive/2007/11/02/35767.htmlshifan3 shifan3 Fri, 02 Nov 2007 10:05:00 GMT http://m.shnenglu.com/shifan3/archive/2007/11/02/35767.html http://m.shnenglu.com/shifan3/comments/35767.html http://m.shnenglu.com/shifan3/archive/2007/11/02/35767.html#Feedback 2 http://m.shnenglu.com/shifan3/comments/commentRss/35767.html http://m.shnenglu.com/shifan3/services/trackbacks/35767.html http://blog.csdn.net/vbvan/archive/2007/10/30/1857134.aspx Flexible C++ C++是一门非常灵zȝ语言Q只要充分发挥你的想象, 再普通的东西都能玩出新花?br> 1?~1000求和 循环Q递归Q再单不q的题目了。但是如果不允许你用判断语句呢? 如果你熟悉switch的内部实玎ͼ那么你很Ҏ惛_使用函数指针数组?br>
#include <cstdio>
typedef int (*fun )(int ); int f1 (int i ) {return 0;} int f2 (int i ) {fun f [2]={f1 ,f2 }; return i +f [!!i ](i -1);} int main () { printf ("%d\n" ,f2 (1000)); }
2、输?,2,...,100,99,...,2,1 如果同样不让你用判断语句呢?你仍然可以用函数指针数l:
#include <cstdio>
typedef void (*fun )(int i ,int n ); void f1 (int i ,int n ); void f2 (int i ,int n ); void f3 (int i ,int n );
void f1 (int i ,int n ) { fun f [2]={f1 ,f2 };
printf ("%d\n" ,i ); f [i +1==n ](i +1,n ); }void f2 (int i ,int n ) { fun f [2]={f2 ,f3 }; printf ("%d\n" ,i ); f [i ==1](i -1,n ); } void f3 (int i ,int n ) {}
int main () { f1 (1,100); }
不过我们有更z的Ҏ?br>短\法和逗号表达式粉墨登ZQ一行搞定~
#include <cstdio>
void f (int i ,int n ) { printf ("%d\n" ,i ),(i <n )&&(f (i +1,n ),printf ("%d\n" ,i )); }
int main () { f (1,100); }
]]> [yc]用户态非抢占式线E库实现 http://m.shnenglu.com/shifan3/archive/2007/03/16/19968.htmlshifan3 shifan3 Fri, 16 Mar 2007 08:33:00 GMT http://m.shnenglu.com/shifan3/archive/2007/03/16/19968.html http://m.shnenglu.com/shifan3/comments/19968.html http://m.shnenglu.com/shifan3/archive/2007/03/16/19968.html#Feedback 4 http://m.shnenglu.com/shifan3/comments/commentRss/19968.html http://m.shnenglu.com/shifan3/services/trackbacks/19968.html 阅读全文 ]]> [yc]垃圾回收QC++资源理杂谈 http://m.shnenglu.com/shifan3/archive/2007/01/24/17963.htmlshifan3 shifan3 Wed, 24 Jan 2007 10:02:00 GMT http://m.shnenglu.com/shifan3/archive/2007/01/24/17963.html http://m.shnenglu.com/shifan3/comments/17963.html http://m.shnenglu.com/shifan3/archive/2007/01/24/17963.html#Feedback 3 http://m.shnenglu.com/shifan3/comments/commentRss/17963.html http://m.shnenglu.com/shifan3/services/trackbacks/17963.html 说到 C/C++ 的资源管理,Zh都会头痛半天。自?/span> C++0x Q就?/span> C++09 了)标准漏出风声之后Q?/span> C++ 标准是否会引入自动垃圑֛收机制就成ؓ了众?/span> C++ 爱好者谈论的话题。但是实际上Q在 C++ 标准的探索上Q垃圑֛收一直处在一个十分低下的C。造成其这一处境的原因很多,也很复杂。我们来看看站在 C++ E序员的角度上看Q资源管理机制现在所面的局ѝ?/span>
从系l结构上来讲Q?/span> C/C++ 支持 3 U内存管理方式,Z栈的自动理Q基于堆的动态管理,和基于全局区的静态管理。由?/span> RAII 的理念,对于 C++ 来说Q内存管理和其他资源理本质上没有区别。因此对于资源而言Q也p然的拥有q样 3 U管理方式?/span>
首先要的介绍一?/span> RAII ?/span> RAII 的全U是 Resource Acquisition Is initialization 。这个思想的基本手法是对于一U想要用的资源Qؓ其书写一?/span> guard c,在该cȝ构造函数里q行资源的请求,在析构函数里q行资源的释放。例如假设我们想理一个互斥锁Q可能的方式是:
struct lock_guard { lock_guard() { lock ();} ~ lock_guard() {unlock();} } ;
此后Q对q个对象使用什么内存管理方式,也就{h于对q个互斥锁用什么内存管理方式?/p>
借助?/span> RAII Q以后我们可以只讨论内存资源的管理方式,其它资源的管理方式可以?/span> RAII 来同L实现。现在我们已l很自然的获得了资源理?/span> 3 U方式:Z堆的动态方式、基于栈的自动方式和全局。值得一提的是,q?/span> 3 U方式中比较不容易出错的后两U实际上可以解决大部分的资源理需求。因为绝大部分资源,都属于获?/span> - 使用 - 释放型的Q例如很多同步对象,文g锁, WinGDI 里的许多 GDI 对象。我们缺乏管理的Q只有那些一ơ获得,多个环境拥有Qƈ且只能有一ơ释攄数资源?/span>
回到内存模型来看Q有一点让我们无法内存与其它资源{同Q反q来Q把其它资源和内存等同却是可以的Q,那就是@环引用?/span> A 内存可以持有指向 B 内存的引用, B 内存也可以反q来持有 A 内存的引用。@环引用导致内存管理不可以?#8220;是否有指向该内存的引?#8221;来区分一块内存是否可以回收。从而׃一个绝佳的理手段。但是在没有循环引用的场合下Q我们还是有非常z高效的理Ҏ的。那是引用计数?/span>
引用计数是在没有循环引用场合下进行内存管理的l佳手段Q它h轻量、高效、即时、可控的优点。而且?/span> C++ 里,引用计数已经非常成熟Q只需要?/span> boost.shared_ptr 或者其它非官方的引用计数指针库可以了Q而且据悉 C++09 很可能把 boost.shared_ptr U_标准库。引用计数的原则是,如果一个对象没有别的指针或引用来指向它Q那么这个对象就是可以释攄。具体的手法有大把大把的资料可以查阅Q这里就不详l说明了。引用计数通常可以处理哪些场合的资源管理问题呢Q首先,对于单方向的资源理Q也是多个 A 的实体拥?/span> 1 ?/span> B Q然?/span> B q不会反q来依赖?/span> A Q例如多个对象共享一个日志)Q引用计数是非常合适的。其ơ,对于拥有 - 反作用的场合Q也是 1 个或多个 A 的实体拥?/span> 1 个或多个 B Q?/span> B 也拥有这?/span> A 的实体的引用Q但?/span> B 的生存期仍然军_?/span> A 的生存期Q例如父H口拥有若干子窗口,子窗口也h parent 指针指向父窗口,但是子窗口的生存期决定于父窗口的生存期)Q这个时?/span> A 可以?/span> B 使用引用计数指针Q?/span> B 可以?/span> A 使用原生的普通指针,同样的可以很好的解决问题?/span>
现在所剩下的,只有生存期的@环依赖了。如?/span> AB 互相持有Ҏ的引用,而且 AB 互相的存在都依赖于对方,q样引用计数无法解决了。但是如果仔l想一下就会发玎ͼq种情况?/span> C++ 里几乎不可能存在。生存期循环依赖只有 2 U后果,要么 A ?/span> B 的析构函数里互相析构Q当然就挂了Q,要么互相都不析构Q当然就泄露了)。而这两种都是在正常编E中不会出现的情c所以如果即使仅仅用引用计敎ͼ我们也可以解军_乎所有的资源理问题?/span>
现在q剩下那么一丁点极少出现的不能处理的情况Q我们可以用更加复杂的 gc 来实现。可惜的是,实现一?/span> gc 所要耗费的精力实在太大,而且几乎不可避免的要成ؓ侵入式的库。所以有点得不偿失。而且 gc 通常会生更多的毛病Q?/span>
1Q?/font> 你无法却知对象析构的具体旉Q从而无法真正知道媄响程序性能的瓶颈在什么地斏V?/span>
2Q?/font> gc 都們于大量的使用内存Q直到内存不够的时候再q行清理Q这样会DE序的内存用量严重颠,q且产生大量的换c?/span>
3Q?/font> q度的依赖于 gc 会ɽE序员大量的把可以由之前提到的各U方法来处理的资源交l?/span> gc 来处理,无故的加重了 gc 的负担?/span>
4Q?/font> gc 的管理方法和 C++ 的析构函数有可能产生语义上的冲突?/span>
q就是ؓ什?/span> C++ 标准对垃圑֛收的态度如此恶劣的原因?/span>
我们现在回过头来?/span> Java/C# q样的内|?/span> gc 的语a。这L语言׃使用?/span> gc Q就不可避免的放弃了析构函数。ؓ什?/span> gc 会和析构函数产生冲突呢?一?/span> gc 一般会希望在进行垃圑֛收的时候,整个q程是一个原子的Q但析构函数会破坏这一点,在释攑ֆ存的时候如果还要执行代码,那么隑օ会对整个 gc 环境产生破坏性的影响。由于没有析构函敎ͼq些语言׃可能做到 RAII Q也是_它们?/span> gc 所能够理的,也就仅仅只有内存而已了。对于其他资源, Java {就必须手动释放。虽?/span> C# 提供?/span> with 关键字来~解q一问题Q但仍然无法d的解冟?/span>
q有什么麻烦呢Q之前说的那 4 点全部都有。虽?/span> JVM 的速度在不断的提高Q但是内存用这一点却完全没有发展Q不能不说是 gc 说导致。它所带来了什么好处呢Q是内存理的自动化Q而不是资源管理的自动化?/span>
所以说 C++ q不是世人所惌的那样需?/span> gc Q?/span> C++ 本n已l提供了_强大的资源管理能力。基于栈的自动管理,或者用引用计敎ͼ几乎可以辑ֈ?/span> gc 同样的覆盖面Q而且没有 gc 的那些问题, RAII 使得 C++ 在管理非内存资源的时候还更加有优势,Z么不使用呢?
ps. 设计一个非官方?/span> gc 库还是可以的。但是毕竟不会成Z了?/span>
]]>[yc]详解link http://m.shnenglu.com/shifan3/archive/2007/01/05/17325.htmlshifan3 shifan3 Fri, 05 Jan 2007 08:03:00 GMT http://m.shnenglu.com/shifan3/archive/2007/01/05/17325.html http://m.shnenglu.com/shifan3/comments/17325.html http://m.shnenglu.com/shifan3/archive/2007/01/05/17325.html#Feedback 4 http://m.shnenglu.com/shifan3/comments/commentRss/17325.html http://m.shnenglu.com/shifan3/services/trackbacks/17325.html 有些人写C/C++(以下假定为C++)E序Q对unresolved external link或者duplicated external simbol的错误信息不知所措(因ؓq样的错误信息不能定位到某一行)。或者对语言的一些部分不知道Z么要Q或者不要)q样那样设计。了解本文之后,或许会有一些答案?br> 首先看看我们是如何写一个程序的。如果你在用某UIDEQVisual StudioQElicpseQDev C++{)Q你可能不会发现E序是如何组lv来的Q很多h因此而反对初学者用IDEQ。因Z用IDEQ你所做的事情Q就是在一个项目里新徏一pd?cpp?h文gQ编写好之后在菜单里点击“~译”Q就万事大吉了。但其实以前Q程序员写程序不是这L。他们首先要打开一个编辑器Q像~写文本文g一L写好代码Q然后在命o行下?br> cc 1.cpp -o 1.o cc 2.cpp -o 2.o cc 3.cpp -o 3.o q里cc代表某个C/C++~译器,后面紧跟着要编译的cpp文gQƈ且以-o指定要输出的文gQ请原谅我没有用Q何一个流行编译器作ؓ例子Q。这样当前目录下׃出现Q?br> 1.o 2.o 3.o 最后,E序员还要键?br> link 1.o 2.o 3.o -o a.out 来生成最l的可执行文件a.out。现在的IDEQ其实也同样늅着q个步骤Q只不过把一切都自动化了?br> 让我们来分析上面的过E,看看能发C么?br> 首先Q对源代码进行编译,是对各个cpp文g单独q行的。对于每一ơ编译,如果排除在cpp文g里include别的cpp文g的情况(q是C++代码~写中极光误的写法Q,那么~译器仅仅知道当前要~译的那一个cpp文gQ对其他的cpp文g的存在完全不知情?br> 其次Q每个cpp文g~译后,产生?o文gQ要被一个链接器(link)所dQ才能最l生成可执行文g?br> 好了Q有了这些感性认识之后,让我们来看看C/C++E序是如何组l的?br> 首先要知道一些概念: ~译Q编译器Ҏ代码q行~译Q是以文本形式存在的源代码译为机器语a形式的目标文件的q程?br> ~译单元Q对于C++来说Q每一个cpp文g是一个编译单元。从之前的编译过E的演示可以看出Q各个编译单元之间是互相不可知的?br> 目标文gQ由~译所生成的文Ӟ以机器码的Ş式包含了~译单元里所有的代码和数据,以及一些其他的信息?br> 下面我们具体看看~译的过E。我们蟩q语法分析等Q直接来到目标文件的生成。假设我们有一?.cpp文g int n = 1; void f() { ++n; } 它编译出来的目标文g1.o׃有一个区域(假定名称?q制D)Q包含了以上数据Q函敎ͼ其中有n, fQ以文g偏移量的形式l出很可能就是: 偏移?nbsp; 内容 长度 0x000 n 4 0x004 f ?? 注意Q这仅仅是猜,不代表目标文件的真实布局。目标文件的各个数据不一定连l,也不一定按照这个顺序,当然也不一定从0x000开始?br> 现在我们看看?x004开始f函数的内容(?x86q_下的猜测Q: 0x004 inc DWORD PTR [0x000] 0x00? ret 注意n++已经被翻译ؓQinc DWORD PTR [0x000]Q也是把本单元0x000位置上的一个DWORD(4字节)??br> 下面如果有另一?.cppQ如?br> extern int n; void g() { ++n; } 那么它的目标文g2.o?q制D就应该?br> 偏移?nbsp; 内容 长度 0x000 g ?? Z么这里没有n的空_也就是n的定义)Q因为n被声明ؓexternQ表明n的定义在别的~译单元里。别忘了~译的时候是不可能知道别的编译单元的情况的,故编译器不知道nI竟在何处,所以这个时候g的二q制代码里没有办法填写inc DWORD PTR [???]中的Q?Q部分。怎么办呢Q这个工作就只能交给后来的链接器d理。ؓ了让链接器知道哪些地方的地址是没有填好的Q所以目标文件还要有一?#8220;未解决符可”Q也是unresolved symbol table. 同样,提供n的定义的目标文g(也就?.o)也要提供一?#8220;导出W号?#8221;Qexport symbol table, 来告诉链接器自己可以提供哪些地址?br> 让我们理一下思\Q现在我们知道,每一个目标文Ӟ除了拥有自己的数据和二进制代码之外,q要臛_提供2个表Q未解决W号表和导出W号表,分别告诉链接器自己需要什么和能够提供什么。下面的问题是,如何?个表之间建立对应关系。这里就有一个新的概念:W号。在C/C++中,每一个变量和函数都有自己的符受例如变量n的符号就?#8220;n”。函数的W号要更加复杂,它需要结合函数名及其参数和调用惯例等Q得C个唯一的字W串。f的符号可能就?_f"Q根据不同编译器可以有变化)?br> 所以,1.o的导出符可是 W号 地址 n 0x000 _f 0x004 而未解决W号表ؓI?br> 2.o的导出符可?br> W号 地址 _g 0x000 未解决符可?br> W号 地址 n 0x001 q里0x001Z0x000开始的inc DWORD PTR [???]的二q制~码中存???的v始地址(q里假设inc的机器码的第2Q?字节+1的绝对地址Q需要知道确切情况可查手?。这个表告诉链接器,在本~译单元0x001的位|上有一个地址Q该地址g明,但是hW号n?br> 链接的时候,链接器在2.o里发C未解决符号nQ那么在查找所有编译单元的时候,?.o中发C导出W号nQ那么链接器׃n的地址0x000填写?.o?x001的位|上?br> “打住”Q可能你׃跛_来指责我了。如果这样做得话Q岂不是g的内容就会变成inc DWORD PTR [0x000]Q按照之前的理解Q这是将本单元的0x000地址?字节?Q而不是将1.o的对应位|加1。是的,因ؓ每个~译单元的地址都是?开始的Q所以最l拼接v来的时候地址会重复。所以链接器会在拼接的时候对各个单元的地址q行调整。这个例子中Q假?.o?x00000000地址被定位在可执行文件的0x00001000上,?.o?x00000000地址被定位在可执行文件的0x00002000上,那么实际上对链接器来_1.o的导出符可其实 W号 地址 n 0x000 + 0x2000 _f 0x004 + 0x2000 而未解决W号表ؓI?br> 2.o的导出符可?br> W号 地址 _g 0x000 + 0x1000 未解决符可?br> W号 地址 n 0x001 + 0x1000 所以最lg的代码会变ؓinc DWORD PTR [0x000 + 0x2000]?br> 最后还有一个漏z,既然最后n的地址变ؓ0x2000了,那么以前f的代码inc DWORD PTR [0x000]是错误的了。所以目标文件ؓ此还要提供一个表Q叫做地址重定向表address redirect table?br> 对于1.o来说Q它的重定向表ؓ 地址 0x005 q个表不需要符P当链接器处理q个表的时候,发现地址?x005的位|上有一个地址需要重定向Q那么直接在?x005开始的4个字节上加上0x2000可以了?br> 让我们ȝ一下:~译器把一个cpp~译为目标文件的时候,除了要在目标文g里写入cpp里包含的数据和代码,q要臛_提供3个表Q未解决W号表,导出W号表和地址重定向表?br> 未解决符可提供了所有在该编译单元里引用但是定义q不在本~译单元里的W号及其出现的地址?br> 导出W号表提供了本编译单元具有定义,q且愿意提供l其他编译单元用的W号及其地址?br> 地址重定向表提供了本~译单元所有对自n地址的引用的记录?br> 链接器进行链接的时候,首先军_各个目标文g在最l可执行文g里的位置。然后访问所有目标文件的地址重定向表Q对其中记录的地址q行重定向(卛_上该~译单元实际在可执行文g里的起始地址Q。然后遍历所有目标文件的未解决符可Qƈ且在所有的导出W号表里查找匚w的符Pq在未解决符可中所记录的位|上填写实际的地址Q也要加上拥有该W号定义的编译单元实际在可执行文仉的v始地址Q。最后把所有的目标文g的内容写在各自的位置上,再作一些别的工作,一个可执行文g出炉了?br> 最llink 1.o 2.o .... 所生成的可执行文g大概?br> 0x00000000 ????Q别的一些信息) .... 0x00001000 inc DWORD PTR [0x00002000] //q里?.o的开始,也就是g的定?br> 0x00001005 ret //假设inc?个字节,q里是g的结?br> .... 0x00002000 0x00000001 //q里?.o的开始,也是n的定义(初始化ؓ1Q?br> 0x00002004 inc DWORD PTR [0x00002000] //q里是f的开?br> 0x00002009 ret //假设inc?个字节,q里是f的结?br> ... ... 实际链接的时候更为复杂,因ؓ实际的目标文仉把数据/代码分ؓ好几个区Q重定向{要按区q行Q但原理是一L?br> 现在我们可以来看看几个经典的链接错误了: unresolved external link.. q个很显Ӟ是链接器发现一个未解决W号Q但是在导出W号表里没有扑ֈ对应的項?br> 解决Ҏ么,当然是在某个编译单元里提供q个W号的定义就行了。(注意Q这个符号可以是一个变量,也可以是一个函敎ͼQ也可以看看是不是有什么该链接的文件没有链?br> duplicated external simbols... q个则是导出W号表里出现了重复项Q因此链接器无法定应该使用哪一个。这可能是用了重复的名Uͼ也可能有别的原因?br> 我们再来看看C/C++语言里针对这一些而提供的Ҏ: extern:q是告诉~译器,q个W号在别的编译单元里定义Q也是要把q个W号攑ֈ未解决符可里去。(外部链接Q?br> static:如果该关键字位于全局函数或者变量的声明的前面,表明该编译单元不导出q个函数Q变量的W号。因此无法在别的~译单元里用。(内部链接Q。如果是static局部变量,则该变量的存储方式和全局变量一P但是仍然不导出符受?br> 默认链接属性:对于函数和变量,模认外部链接Q对于const变量Q默认内部链接。(可以通过dextern和static改变链接属性) 外部链接的利弊:外部链接的符P可以在整个程序范围内使用Q因为导ZW号Q。但是同时要求其他的~译单元不能导出相同的符P不然是duplicated external simbols) 内部链接的利弊:内部链接的符P不能在别的编译单元内使用。但是不同的~译单元可以拥有同样名称的内部链接符受?br> Z么头文g里一般只可以有声明不能有定义Q头文g可以被多个编译单元包含,如果头文仉有定义,那么每个包含q个头文件的~译单元都会对同一个符可行定义,如果该符号ؓ外部链接Q则会导致duplicated external simbols。因此如果头文g里要定义Q必M证定义的W号只能h内部链接?br> Z么常量默认ؓ内部链接Q而变量不是: q就是ؓ了能够在头文仉如const int n = 0q样的定义常量。由于常量是只读的,因此即每个~译单元都拥有一份定义也没有关系。如果一个定义于头文仉的变量拥有内部链接,那么如果出现多个~译单元都定义该变量Q则其中一个编译单元对该变量进行修改,不会影响其他单元的同一变量Q会产生意想不到的后果?br> Z么函数默认是外部链接Q?br> 虽然函数是只ȝQ但是和变量不同Q函数在代码~写的时候非常容易变化,如果函数默认h内部链接Q则Z会們于把函数定义在头文g里,那么一旦函数被修改Q所有包含了该头文g的编译单元都要被重新~译。另外,函数里定义的静态局部变量也被定义在头文g里?br> Z么类的静态变量不可以地初始化:所谓就地初始化是cM于这L情况Q?br> class A { static char msg[] = "aha"; }; 不允许这样做得原因是Q由于class的声明通常是在头文仉Q如果允许这样做Q其实就相当于在头文仉定义了一个非const变量?br> 在C++里,头文件定义一个const对象会怎么P 一般不会怎么Pq个和C里的在头文g里定义const int一P每一个包含了q个头文件的~译单元都会定义q个对象。但׃该对象是const的,所以没什么媄响。但是:?U情况可能破坏这个局面: 1。如果涉及到对这个const对象取地址q且依赖于这个地址的唯一性,那么在不同的~译单元里,取到的地址可以不同。(但一般很这么做Q?br> 2。如果这个对象具有mutable的变量,某个~译单元对其q行修改Q则同样不会影响到别的编译单元?br> Z么类的静态常量也不可以就地初始化Q?br> 因ؓq相当于在头文g里定义了const对象。作Z外,int/char{可以进行就地初始化Q是因ؓq些变量可以直接被优化ؓ立即敎ͼ和宏一栗?br> 内联函数Q?br> C++里的内联函数׃cM于一个宏Q因此不存在链接属性问题?br> Z么公׃用的内联函数要定义于头文仉Q?br> 因ؓ~译时编译单元之间互怸知道Q如果内联函数被定义?cpp文g中,~译其他使用该函数的~译单元的时候没有办法找到函数的定义Q因此无法对函数q行展开。所以说如果内联函数定义?cpp文g里,那么只有这个cpp文g可以是用q个函数?br> 头文仉内联函数被拒l会怎样Q?br> 如果定义于头文g里的内联函数被拒l,那么~译器会自动在每个包含了该头文g的编译单元里定义q个函数q且不导出符受?br> 如果被拒l的内联函数里定义了静态局部变量,q个变量会被定义于何处: 早期的编译器会在每个~译单元里定义一个,q因此生错误的l果Q较新的~译器会解决q个问题Q手D|知?br> Z么export关键字没人实玎ͼ export要求~译器跨~译单元查找函数定义Q得编译器实现非常困难?br> ~译和静态链接就分析到这里,我会带着动态链接和load的详解杀回来
]]> [yc]ȝ一下C++的名U查N?/title> http://m.shnenglu.com/shifan3/archive/2006/12/27/16902.htmlshifan3 shifan3 Wed, 27 Dec 2006 03:04:00 GMT http://m.shnenglu.com/shifan3/archive/2006/12/27/16902.html http://m.shnenglu.com/shifan3/comments/16902.html http://m.shnenglu.com/shifan3/archive/2006/12/27/16902.html#Feedback 8 http://m.shnenglu.com/shifan3/comments/commentRss/16902.html http://m.shnenglu.com/shifan3/services/trackbacks/16902.html 阅读全文 ]]> [yc]伪typeof http://m.shnenglu.com/shifan3/archive/2006/12/21/16690.htmlshifan3 shifan3 Thu, 21 Dec 2006 06:29:00 GMT http://m.shnenglu.com/shifan3/archive/2006/12/21/16690.html http://m.shnenglu.com/shifan3/comments/16690.html http://m.shnenglu.com/shifan3/archive/2006/12/21/16690.html#Feedback 5 http://m.shnenglu.com/shifan3/comments/commentRss/16690.html http://m.shnenglu.com/shifan3/services/trackbacks/16690.html 发信? shifan (学习云技?, 杉K: C++ ?nbsp; ? 伪typeof 发信? 飘ؓ水云?(Tue Dec 19 16:38:45 2006), 转信
1 /* 2 用标准C++实现typeof是不可能?br> 3 q个是我写的一个approached typeof 4 所有需要被静态反出来的cd必须先用DECL_TYPE注册 5 模板如果仅仅带有1个参数可以用DECL_TEMPLATE_1注册 6 多个参数的模板还不支持。?br> 7 主要是没惛_~码 8 9 d能注?4个类?br> 10 可以通过MAX_TYPE_NUMBER讄 11 12 支持的模板嵌套层数大Uؓ32 Q?nbsp;log2(MAX_TYPE_NUMBER) 13 MAX_TYPE_NUMBER必须?的整ơ数q?br> 14 */ 15 namespace my_typeof 16 { 17 18 const int MAX_TYPE_NUMBER = 64 ; 19 20 template < int N > 21 struct dummy 22 { 23 int a[N]; 24 }; 25 26 27 template < int N, typename Arg1 > 28 struct select_by_number_1; 29 30 template < int N > 31 struct select_by_number 32 { 33 typedef typename select_by_number_1 < N % MAX_TYPE_NUMBER, typename 34 select_by_number < N / MAX_TYPE_NUMBER > ::type > ::type type; 35 }; 36 37 38 template < typename T > 39 struct number_of 40 { 41 static const int v = sizeof (generic_f( * (T * ) 0 )) / sizeof ( int ); 42 }; 43 44 45 #define DECL_TYPE(T, N) \ 46 namespace my_typeof{ \ 47 template <> \ 48 struct select_by_number < N > \ 49 {\ 50 typedef T type;\ 51 };\ 52 dummy < N > generic_f( const T & );} 53 54 55 #define DECL_TEMPLATE_1(T, N) \ 56 namespace my_typeof{ \ 57 template < typename Arg1 > \ 58 struct select_by_number_1 < N, Arg1 > \ 59 {\ 60 typedef T < Arg1 > type;\ 61 };\ 62 template < typename Arg1 > \ 63 dummy < N + number_of < Arg1 > ::v * MAX_TYPE_NUMBER > generic_f( const T < Arg1 >& );} 64 65 66 67 #define TYPE_OF(x) my_typeof::select_by_number<sizeof(my_typeof::generic_f(x)) / 68 sizeof ( int ) > ::type 69 70 } 71 72 73 // sample 74 #include < iostream > 75 #include < vector > 76 #include < list > 77 78 79 DECL_TYPE( int , 1 ); 80 DECL_TEMPLATE_1(std::vector, 2 ); 81 DECL_TEMPLATE_1(std::list, 3 ); 82 DECL_TYPE( double , 4 ) 83 84 using namespace std; 85 int main( int , char * []) 86 { 87 vector < list < vector < list < double > > > > v1; 88 TYPE_OF(v1) v2; 89 v1 = v2; 90 return 0 ; 91 } 92 93
-- You well 撒法QYou well all 撒法Q?br> ?内容修改:·shifan ?Dec 21 14:21:57 修改本文内容·[FROM: shifan] ?来源:·飘ؓ水云?freecity.cn·[FROM: shifan]
]]>[yc]Multi Bit Mask http://m.shnenglu.com/shifan3/archive/2006/10/26/14264.htmlshifan3 shifan3 Thu, 26 Oct 2006 15:37:00 GMT http://m.shnenglu.com/shifan3/archive/2006/10/26/14264.html http://m.shnenglu.com/shifan3/comments/14264.html http://m.shnenglu.com/shifan3/archive/2006/10/26/14264.html#Feedback 2 http://m.shnenglu.com/shifan3/comments/commentRss/14264.html http://m.shnenglu.com/shifan3/services/trackbacks/14264.html boost的integer/integer_mask.hpp仅仅做了单个位的bit mask 要多个位必须写很多遍high_bit_mask_t 使用low_bits_mask_t也不能完全解决问?br>所以自qTypelist的U写法写了一?/p>
用法举例 bit_mask<INT_LIST_2(2, 3)>::valueq回一个|该值的W??位被|ؓ1 其余位ؓ0
1 2 namespace multi_bit_mask 3 { 4 namespace details 5 { 6 7 template < typename T > 8 struct get_size 9 { 10 enum {size = sizeof (T)}; 11 }; 12 13 template < int Bit > 14 struct bit_storage 15 { 16 typedef typename bit_storage < Bit - 1 > ::storage_type storage_type; 17 }; 18 19 // ---------platform dependency----------------------- 20 21 typedef unsigned int smallest_storage_type; 22 typedef unsigned long long largest_storage_type; 23 24 25 26 template <> 27 struct bit_storage < 0 > 28 { 29 typedef smallest_storage_type storage_type; 30 }; 31 32 template <> 33 struct bit_storage < get_size < smallest_storage_type > ::size * 8 > 34 { 35 typedef largest_storage_type storage_type; 36 }; 37 38 // disable the 65th bit 39 template <> 40 struct bit_storage < get_size < largest_storage_type > ::size * 8 > 41 { 42 typedef void storage_type; 43 }; 44 45 // ---------end of platform dependency---------------- 46 47 48 template < unsigned int N, typename Next > 49 struct int_list 50 { 51 typedef typename bit_storage < N > ::storage_type storage_type; 52 static const storage_type value = N; 53 typedef Next next; 54 }; 55 56 struct null_type{}; 57 58 template < typename T1, typename T2, bool is_first > 59 struct selector 60 { 61 typedef T1 type; 62 }; 63 64 template < typename T1, typename T2 > 65 struct compare_type 66 { 67 const static bool is_larger = sizeof (T1) > sizeof (T2); 68 typedef typename selector < T1, T2, is_larger > ::type large_type; 69 typedef typename selector < T1, T2, ! is_larger > ::type small_type; 70 }; 71 72 73 74 template < typename T1, typename T2 > 75 struct selector < T1, T2, false > 76 { 77 typedef T2 type; 78 }; 79 80 template < typename List > 81 class find_largest_storage 82 { 83 typedef typename find_largest_storage < typename List::next > ::storage_type T1; 84 typedef typename bit_storage < List::value > ::storage_type T2; 85 public : 86 typedef typename compare_type < T1, T2 > ::large_type storage_type; 87 }; 88 89 template <> 90 class find_largest_storage < null_type > 91 { 92 public : 93 typedef smallest_storage_type storage_type; 94 }; 95 96 97 } 98 99 100 101 102 103 template < int N > 104 struct single_bit_mask 105 { 106 typedef typename details::bit_storage < N > ::storage_type storage_type; 107 static const storage_type value 108 = static_cast < storage_type > (single_bit_mask < N - 1 > ::value) * 2 ; 109 }; 110 111 template <> 112 struct single_bit_mask < 0 > 113 { 114 typedef details::bit_storage < 0 > ::storage_type storage_type; 115 static const storage_type value = 1 ; 116 }; 117 118 119 typedef details::null_type null_type; 120 121 template < int N, typename Next > 122 struct int_list_t : public details::int_list < N, Next > {}; 123 124 template < typename List > 125 struct bit_mask 126 { 127 public : 128 129 typedef typename details::find_largest_storage < List > ::storage_type storage_type; 130 131 static const storage_type value 132 = static_cast < storage_type > (single_bit_mask < List::value > ::value) 133 | static_cast < storage_type > (bit_mask < typename List::next > ::value); 134 }; 135 136 template <> 137 struct bit_mask < null_type > 138 { 139 typedef details::bit_storage < 0 > ::storage_type storage_type; 140 static const storage_type value = 0 ; 141 }; 142 143 144 145 146 147 #define INT_LIST_1(n1) multi_bit_mask::int_list_t<n1, multi_bit_mask::null_type> 148 #define INT_LIST_2(n1, n2) multi_bit_mask::int_list_t<n1, INT_LIST_1(n2) > 149 #define INT_LIST_3(n1, n2, n3) multi_bit_mask::int_list_t<n1, INT_LIST_2(n2, n3) > 150 #define INT_LIST_4(n1, n2, n3, n4) multi_bit_mask::int_list_t<n1, INT_LIST_3(n2, n3, n4) > 151 #define INT_LIST_5(n1, n2, n3, n4, n5) multi_bit_mask::int_list_t<n1, INT_LIST_4(n2, n3, n4, n5) > 152 #define INT_LIST_6(n1, n2, n3, n4, n5, n6) multi_bit_mask::int_list_t<n1, INT_LIST_5(n2, n3, n4, n5, n6) > 153 #define INT_LIST_7(n1, n2, n3, n4, n5, n6, n7) multi_bit_mask::int_list_t<n1, INT_LIST_6(n2, n3, n4, n5, n6, n7) > 154 #define INT_LIST_8(n1, n2, n3, n4, n5, n6, n7, n8) multi_bit_mask::int_list_t<n1, INT_LIST_7(n2, n3, n4, n5, n6, n7, n8) > 155 156 } 157 158 159
sample
#include < iostream > #include " multi_bit_mask.h " using namespace std; int main() { cout << multi_bit_mask::bit_mask < INT_LIST_1( 1 ) > ::value << endl; cout << multi_bit_mask::bit_mask < INT_LIST_5( 0 , 1 , 2 , 3 , 4 ) > ::value << endl; cout << multi_bit_mask::bit_mask < INT_LIST_7( 0 , 1 , 2 , 3 , 4 , 4 , 2 ) > ::value << endl;
]]> [yc]VC下typeid实现及内存布局分析 http://m.shnenglu.com/shifan3/archive/2006/10/26/14187.htmlshifan3 shifan3 Thu, 26 Oct 2006 02:46:00 GMT http://m.shnenglu.com/shifan3/archive/2006/10/26/14187.html http://m.shnenglu.com/shifan3/comments/14187.html http://m.shnenglu.com/shifan3/archive/2006/10/26/14187.html#Feedback 5 http://m.shnenglu.com/shifan3/comments/commentRss/14187.html http://m.shnenglu.com/shifan3/services/trackbacks/14187.html q日在学校bbs上与论C++的typeid关键字的实现问题Q有人提到type_info的地址是存攑֜虚表的第一个位|上Q颇觉得不妥Q于是我在vc2003下实验了一?/p>
在vc下,使用typeid的时候,如果typeid施加l的cd是没有vptr的class或者根本不是class 那么汇编?br>mov dword ptr [addr],offset A `RTTI Type Descriptor' (42AD40h) 也就是编译器生成一个简单的type_info对象的表Qƈ且在~译期静态决定下标,做一个简单查表操作?br>
如果typeid的操作对象是hvptr的classQ但是ƈ不是一个引用或者指针的解引用Ş式,例如
A a; typeid(a);
那么仍然仅仅会做查表操作 如果typeid的操作对象是hvptr的classQƈ且是引用或者指针的解引用Ş式,例如
A * p = new A; A & r = * p; typeid( * p); typeid(r);
那么׃调用一个叫___RTtypeid的函敎ͼq过某种Ҏ来获取type_info对象 下面是___RTtypeid的反汇编Q这里只列出关键的几条指?br>
0041213E mov ecx,dword ptr [inptr] Qinptr是对象的地址 00412141 mov edx,dword ptr [ecx] 00412143 mov eax,dword ptr [edx - 4 ] 0041215F mov ecx,dword ptr [eax + 0Ch] 00412162 mov dword ptr [ebp - 48h],ecx 0041216C mov eax,dword ptr [ebp - 48h]
基本上等价于C语言?br>
int a1 = ( int )p; // p是对象的地址 int a2 = * ( int * )a1 - 4 ; int a3 = * ( int * )a2 + 12 ; int a4 = * ( int * )a3;
那么从这D代码可以看出vc下type_info对象的存放位|[如下图]
也就虚表下标?1的位|上存放了一个指向一个未知的表的指针(暂且此表命名ؓruntime_info_table) runtime_info_table的第4g存放了type_info对象的地址 至于runtime_info_table里前3g存放的是什? q需要再研究研究 一般来说它们全?, 但是对于多重虚承的c? W二g会是4, 可能和指针的偏移量有?
]]> [yc]Xpressive?/title> http://m.shnenglu.com/shifan3/archive/2006/07/27/10590.htmlshifan3 shifan3 Thu, 27 Jul 2006 08:27:00 GMT http://m.shnenglu.com/shifan3/archive/2006/07/27/10590.html http://m.shnenglu.com/shifan3/comments/10590.html http://m.shnenglu.com/shifan3/archive/2006/07/27/10590.html#Feedback 4 http://m.shnenglu.com/shifan3/comments/commentRss/10590.html http://m.shnenglu.com/shifan3/services/trackbacks/10590.html Xpressive和Boost.Regex的区别很大。首先,Xpressive是一个纯头文件的库,也是_在用之前不需要预先编译。其ơ,Xpressive支持cM于Spirit的静态语义定义?br> 我们先来看一个例子:
#include < iostream > #include < boost / xpressive / xpressive.hpp > using namespace boost::xpressive; int main() { std:: string hello( " hello world! " ); sregex rex = sregex::compile( " (\\w+) (\\w+)! " ); smatch what; if ( regex_match( hello, what, rex ) ) { std::cout << what[ 0 ] << ' \n ' ; // whole match std::cout << what[ 1 ] << ' \n ' ; // first capture std::cout << what[ 2 ] << ' \n ' ; // second capture } return 0 ; }
q是使用Xpressive动态语义定义的例子Q其中sregex::compile函数~译一个表C正则文法的Ԍq返回一个正则对象sregex 使用regex_match来用这个正则对象匹配一个串。结果储存在what?br>其中what[0]q回整个Ԍwhat[1]~what[n]q回文法中用于标记的部分(用小括号括v来的部分) 最后将输出 hello world! hello world
如果惛_一个串中查扄合该文法的子Ԍ可以使用regex_searchQ用法和regex_match一P此外q可以用regex_replace来进行替换?br>
静态文法: Xpressive除了可以用compile来分析一个文法串之外Q还可以用类gSpirit的方式来静态的指定文法Q?br>
sregex re = ' $ ' >> + _d >> ' . ' >> _d >> _d;
q将定义一个表C金额的Ԍ其中_d表示一个数字,相当于串 $\d+.\d\d q样定义文法比之前的动态定义更加高效,q且q有一个附加的好处Q?br>分定义Q?/p>
sregex re = ' $ ' >> + _d >> ' . ' >> _d >> _d; sregex s = ' ( ' >> re >> ' ) ' ;
q样s表示为用括号括v来的re 通过分定义Q文法能被表C的更加清楚?br>更加的是,分定义q可以向后引用,因此能够分析EBNF
sregex group, factor, term, expression; group = ' ( ' >> by_ref(expression) >> ' ) ' ; factor = + _d | group; term = factor >> * (( ' * ' >> factor) | ( ' / ' >> factor)); expression = term >> * (( ' + ' >> term) | ( ' - ' >> term));
expression定义了一个四则表辑ּQ注意其中group的定义?br>q里必须使用by_ref是因为Xpressive默认是值拷贝,如果q里使用默认的方式,那么会造成一个无限@环?br> Xpressive可以在这里下?br>http://boost-consulting.com/vault/index.php?PHPSESSID=f1d4af8b742cfa7adae7aab373cfc535&direction=0&order=&directory=Strings%20-%20Text%20Processing&PHPSESSID=f1d4af8b742cfa7adae7aab373cfc535 内有详细的文?/p>
]]> [yc]乱序Policy手法 http://m.shnenglu.com/shifan3/archive/2006/07/24/10384.htmlshifan3 shifan3 Sun, 23 Jul 2006 17:06:00 GMT http://m.shnenglu.com/shifan3/archive/2006/07/24/10384.html http://m.shnenglu.com/shifan3/comments/10384.html http://m.shnenglu.com/shifan3/archive/2006/07/24/10384.html#Feedback 8 http://m.shnenglu.com/shifan3/comments/commentRss/10384.html http://m.shnenglu.com/shifan3/services/trackbacks/10384.html 看了546@C++@Freecity 之后Q发觉非常有意?由此产生一些想?/p>
很多时候写一个类的时候,需要多个模版参敎ͼ例如一个遗传算法的法c,需要一个模版参数来指定交配方式Q另一个模版参数来指定子代选择的方式,q要一个参数来指定变异的方式。那么一般来_q个cM写成Q?/p>
template<class T //描述问题的一个类 , class CrossPolicy = AvgCrossPolicy //杂交方式 , class SelectPolicy = DefaultSelectPolicy //子代选择的方?br> , class VariationPolicy = ReverseVariationPolicy> //变异方式 class Gene : private AvgCrossPolicy , private SelectPolicy , private VariationPolicy { .... };
q样用户要用该cȝ时候,可以直接指定TQ就行了Q然而如果要指定变异方式Q那么就必须把所有的参数都显式的写出来,很不方便
546提供了一U有效的ҎQ可以让我们仅仅指定变异参数Q而不用写出另两个Policy 甚至允许我们以Q意的序书写几个Policy参数Q都不会有问?/p>
预备知识: TypeList 一个TypeList是一个类型的容器 template <typename Type_, typename Next_> struct TypeList { typedef Type_ Type; typedef Next_ Next; }; q就是一个TypeList?br>看这个写法,是不是像一个链表? 首先定义一个类型来表示链表:class NullType{}; 现在一个包含了2个类型的TypeList可以写为: TypeList<T1, TypeList<T2, NullType> >
如何在一个TypeList中查找一个类型的子类Q?br>首先要有一个IsDerivedFrom<Base, T> q个比较?br>template<class Base, class T> class IsDerivedFrom { struct large{char a[2];}; static char pred(Base*); static large pred(...); public: enum {Is = sizeof(pred((T*)0)) == sizeof(char)}; };
然后FindChild容易了 template <class List, class Base> struct FindChild { template <bool IsChild> struct Select { typedef typename List::Type Type; };
template <> struct Select<false> { typedef typename FindChild<typename List::Next, Base>::Type Type; };
typedef typename Select<IsDerivedFrom<Base, typename List::Type> >::Type Type; };
当然q要对一些特D情况进行特化,例如NullType template <class Base> struct FindChild<NullType, Base> { typedef NullType Type; }; q里使用NullType来表明没扑ֈ
实际操作Q?br>首先需要给3个Policy3个基c,分别?br>class AvgCrossPolicyBase{}; class SelectPolicyBase{}; class VariationPolicyBase{}; 内容为空p了,q样也没有虚函数调用的开销
然后声明一个类来表C默认情况: class DefaultPolicy{};
定义一个宏 #define TYPELIST_3_N(a, b, c) TypeList<a, TypeList<b, TypeList<c, NullType> > >
下面要写一些选择?用于把合适的cd选择出来Q如果没扑ֈQ则要用默认的cd template <class List, class Base, class DefaultType> struct Selector { template <class RetType> struct Judge { typedef RetType Type; }; template<> struct Judge<NullType> { typedef DefaultType Type; }; typedef typename Judge<typename FindChild<List, Base>::Type >::Type Type; };
好啦Q现在整个类的声明可以写?/p>
template<class T , class CrossPolicy_ = DefaultPolicy , class SelectPolicy_ = DefaultPolicy , class VariationPolicy_ = DefaultPolicy //其后的参数用户不可指?br> , class List = TYPELIST_3_N(CrossPolicy_, SelectPolicy_, VariationPolicy_) , class CrossPolicy = typename Selector<List, CrossPolicyBase, AvgCrossPolicy>::Type , class SelectPolicy = typename Selector<List, SelectPolicyBase, DefaultSelectPolicy>::Type , class VariationPolicy = typename Selector<List, VariationPolicyBase, ReverseVariationPolicy>::Type > class Gene : private CrossPolicy , private SelectPolicy , private VariationPolicy { .... };
其中W?-7个参敎ͼListQCrossPolicyQSelectPolicy和VariationPolicyQ是不由用户指定的,仅仅是ؓ了v一个别?br>W一个参数T必须指定Q然?Q?Q?q?个参数就可以L的改变顺序了 例如Q可以写Gene<T, DefaultSelectPolicy, AvgCrossPolicy>而不会有M问题 如果不想要最后面几个参数的话也行Q但是代码就要稍微长一?br>而且最好在c里面进?个typedef typedef typename Selector<List, CrossPolicyBase, AvgCrossPolicy>::Type CrossPolicy; {,以便在实现的时候?/p>
]]> [yc]自己实现LambdaQ第二部分) http://m.shnenglu.com/shifan3/archive/2006/07/15/10099.htmlshifan3 shifan3 Sat, 15 Jul 2006 07:32:00 GMT http://m.shnenglu.com/shifan3/archive/2006/07/15/10099.html http://m.shnenglu.com/shifan3/comments/10099.html http://m.shnenglu.com/shifan3/archive/2006/07/15/10099.html#Feedback 0 http://m.shnenglu.com/shifan3/comments/commentRss/10099.html http://m.shnenglu.com/shifan3/services/trackbacks/10099.html 阅读全文 ]]> [yc]自己实现Lambda http://m.shnenglu.com/shifan3/archive/2006/06/09/8334.htmlshifan3 shifan3 Fri, 09 Jun 2006 05:23:00 GMT http://m.shnenglu.com/shifan3/archive/2006/06/09/8334.html http://m.shnenglu.com/shifan3/comments/8334.html http://m.shnenglu.com/shifan3/archive/2006/06/09/8334.html#Feedback 6 http://m.shnenglu.com/shifan3/comments/commentRss/8334.html http://m.shnenglu.com/shifan3/services/trackbacks/8334.html 阅读全文 ]]> [yc]boost::spirit初体?/title> http://m.shnenglu.com/shifan3/archive/2005/12/18/1857.htmlshifan3 shifan3 Sun, 18 Dec 2005 04:02:00 GMT http://m.shnenglu.com/shifan3/archive/2005/12/18/1857.html http://m.shnenglu.com/shifan3/comments/1857.html http://m.shnenglu.com/shifan3/archive/2005/12/18/1857.html#Feedback 5 http://m.shnenglu.com/shifan3/comments/commentRss/1857.html http://m.shnenglu.com/shifan3/services/trackbacks/1857.html 最qؓ了解析SQL语法Q怀着试一试的心态去Mboost的spirit库,因ؓ该库的文的介里写着LL parser framework represents parsers directly as EBNF grammars in inlined C++。看着frameworkq个词自然觉得这个库很牛BQ试用了一下果然如此?br> 所谓EBNFx展巴克斯范式Q是一U描qContext-Free Language的文法。在目前常见的非自然语言中,大部分都可以用EBNF表示。例如: group ::= '(' exp ')' factor ::= integer | group term ::= factor (( '*' factor ) | ( '/' factor ))* exp ::= term (( '+' term ) | ( '-' term ))* q是一个整数表辑ּ的EBNF。该D|q用spirit在C++中的实现则是Q?br>
rule <> group, factor, term, exp; group = ' ( ' >> exp >> ' ) ' ; factor = int_p | group; term = factor >> * (( ' * ' >> factor) | ( ' / ' >> factor)); exp = term >> * (( ' + ' >> term) | ( ' - ' >> term));
q里使用=代替::=, ?gt;>代替I格q接。ƈ且由于C++语法所限,EBNF中后|的*在spirit中改为前|?br>{式左边的单词被UCؓ一个ruleQ等式右边ؓrule的定义。我们可以看Z个group是一个exp加上一ҎP一个factor是一个整数或者一个group,一个term是一个或多个factor?/q接Q一个exp是一个或多个term?-q接。处于最端的exp可以据此识别Z下表辑ּ
12345 - 12345 + 12345 1 + 2 1 * 2 1 / 2 + 3 / 4 1 + 2 + 3 + 4 1 * 2 * 3 * 4 (1 + 2 ) * ( 3 + 4 ) ( - 1 + 2 ) * ( 3 + - 4 ) 1 + (( 6 * 200 ) - 20 ) / 6 (1 + ( 2 + ( 3 + ( 4 + 5 ))))
得到一个rule之后Q我们就可以?/font> parse函数对一个串q行识别了。例?br>
parse( " (1 + (2 + (3 + (4 + 5)))) " , exp);
该函数返回一个结构parse_infoQ可以通过讉K其中的full成员来判断是否成功识别,也可以访问stop成员来获知失败的位置。这里要特别提一点,关于各个W号之间的空|spirit的文的正文说的是给parse再传一个参数space_pQ通知parse跌所有的I格Q然而在FAQ中又提到Q如果用以上方法定义ruleQ第三个参数传space_p会失败。原因是使用rule默认定义的规则被UCؓcharacter level parsingQ即字符U别解析Q而parse的第3个参C适用于phrase level parsingQ即语法U别解析。要使用W?个参数可以有几种Ҏ?br> 1。在parse的第二个参数直接传入一个EBNF表达式,不创建rule对象?br>
parse( " hello world " , * anychar_p, space_p);
2。以rule<phrase_scanner_t>创徏rule?br>
rule < phrase_scanner_t > exp;
注意虽然可以用这两个办法屏蔽I格Q但是这样可能完全改变EBNF文法的语义,其是在语言本n需要识别空格的时候。对于这U情况,可以不用第三个参数Qƈ在需要出现空格的地方加上space_p,或?space_p?space_pQ其??分别表示后面的符可l出Cơ以上和0ơ以上。例如一个以I格分隔的整数列表可以写成int_p >> *(+space_p >> int_p) 如上使用parse可以识别一个串Q但q不能做更多的操作,例如语法里的各个成分提取出来。对于这L需求,可以通过actor实现。下面是使用actor的一个简单例?br>
bool parse_numbers(char const * str, vector < double >& v) { return parse(str, // Begin grammar ( real_p[push_back_a(v)] >> * ( ' , ' >> real_p[push_back_a(v)]) ) , // End grammar space_p).full; }
注意?span class=identifier>real_p后面的[]Q中括号里面是一个仿函数Q函数指针或者函数对象)Q该仿函数具有如下调用型?br>
void operator ()(IterT first, IterT last) const ; void operator ()(NumT val) const ; void operator ()(CharT ch) const ;
一旦spase发现了匹?span class=identifier>real_p的子Ԍ׃调用该functor。不同的rule可能会对应不同的调用型别?/span> W一个型别针对一般规则,first和lastZ个指向字W的q代器(一般ؓchar*Q?匚w的子串ؓ[first, last) W二个型别针Ҏ字型规则Q如real_p和int_p, 参数val是一个数字类型?br>W三个性别针对单字W型规则Q如space_p, 参数ch是一个字W类型?br>real_p [ push_back_a ( v )]中的push_back_a是一个spirit已经定义好的functorQ它会将匚w好的内容依照匚w到的旉序调用v的push_back函数加入到v中?br> 到此spirit的常用功能就都介l完了。要详细深入了解可以参考spirit的文档?br> 最后在题一个注意要炏Vspirit的各UEBNFq接都是指针q接Q因此才能在expression被赋值前在group的定义里面用。所以在使用EBNF的时候一定要心不要局部变量的rule提供l全局或者类成员变量使用Q例如:
class A { rule <> s; A() { rule <> r = int_p | hex_p; s = r >> * ( + space_p >> r); // error, r destructed after return } };
如果真想使用局部作用域Q可以在局部的rule前面加上static.
]]>
97Ʒ˾þþô߽97 |
re99þ6Ʒ |
þþƷ˘AV |
ձƷһþþ |
þþƷƵ |
˾þۺ |
Ʒ99þ99þþ |
þݺҹҹվ |
ŷۺϾþþ |
鶹WWWþöڲƷ |
ƷAVþۺӰԺ |
91þþþþۺ |
һþþƷ |
þþƷavӰԺ |
þþþþAvӰԺ |
Ʒžžžþþž |
þ99Ļþ |
ձƷþþþĻ |
LƷþ |
99þþƷѿ |
ƷŮþþþavˬ |
þþƷWWW456C0M |
þˬ˾ƷƵ |
һþþƷһ |
Ʒþþþþ |
Avþ |
þۺϾɫۺϾƷ |
þ99Ʒŷ |
þþžѸƵ |
þۺϾƷþ |
þþþþëƬѲ |
ŮƷþþ |
ŷԴսþþþþ
|
þþƷavպ |
avþþþòվ |
þ99Ʒһ |
þAVԴվ |
AVþþƷ |
ŷƷһþ˵ |
ɫ͵͵88ŷƷþþ |
ھƷþþþþ99 |