??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲Av无码国产情品久久,伊人色综合久久天天网,久久夜色精品国产噜噜噜亚洲AVhttp://www.shnenglu.com/huaxiazhihuo/category/21252.htmlzh-cnWed, 05 Jul 2017 06:10:31 GMTWed, 05 Jul 2017 06:10:31 GMT60完备的运行时cd信息http://www.shnenglu.com/huaxiazhihuo/archive/2017/07/05/215052.html华夏之火华夏之火Wed, 05 Jul 2017 03:45:00 GMThttp://www.shnenglu.com/huaxiazhihuo/archive/2017/07/05/215052.htmlhttp://www.shnenglu.com/huaxiazhihuo/comments/215052.htmlhttp://www.shnenglu.com/huaxiazhihuo/archive/2017/07/05/215052.html#Feedback0http://www.shnenglu.com/huaxiazhihuo/comments/commentRss/215052.htmlhttp://www.shnenglu.com/huaxiazhihuo/services/trackbacks/215052.html众所周知Q码猿写代码Q自然要求严谨周密,D不知想象力也很重要。本座阅码几十年Q很是感概很多码猿的脑洞被大大禁锢,鲜有雷池一步,特别是c++的同学,q同委员会的那一坨老头子,都很让h无语xQ出自这些h的作品,都是一个死鱼眼睛样子,千h一面,毫无灵动之生可a。stlQboostq些库都是这样子Q虽然它们确实可以完成大多数日常dQ,更别说其他的库,没有什么让目一C处?br />
p说动态类型信息这块,又或者说是反。自Ӟ语言本n提供的废物type_info懒得说了,除了证明c++也东施效颦,也能支持动态信息之外,别无用处了Q有谁会正儿八经的用type_info做点正儿八经的事情呢。因此,各\人马UL上阵Q都要I补c++在运行时cd信息上的~失。因为类型的反射信息实在太重要,或者说Q反的用武之地太多太多Q表面上很多事情不需要反,或者字面代码上q不到反射的痕q,但是内里的实玎ͼ大把大把的反在发光发热。c++坚持不在动态信息上l予一点点多余的支持,q不表示c++׃需要反了Q看看标准库q个极力回避动多态的典范Q是一个怎样的失败作品,嗯,q个以后再谈吧。假如stl一开始就没有如此大力排斥动多态,你看看就q内存分配的allocator都可以做到静态类型信息里面(最新版的c++l于也要接受多态的allocatorQc++界居然一片欢呼鼓舞,真是悲哀Q,今时今日的c++׃会在很多领域上到处割地求和?br />
ȝ来说Q现在市面上的c++反射库,都是侵入式,都学着mfc那一套,都是要求l承自一个基cObjectQ然后才能对外提供反信息的功能Q先不说它们提供的类型信息是否完备,q样子就把用途广泛限制死在一个很H很H的圈子里面了。这些反库Q?、不能反基本类型,int、char、double、const char*?#8230;…{;2、不能反非l承自Object的class或者structQ?、也不能反射模板c,比如vector<int>、list<vector<vector<int>>>。虽然typeid千般弱鸡Q但也非一无是处,L非R入、^{、多态。所以,理想的反,应该像c++原生的typeid那样无色无味Q?、非侵入式的Q?、可以对所有的cd都提供反,基本cd、非Objectpȝstruct或者class、templatecd的;3、多态的Q只要改cd需要运行时的类型识别,那么p回其本n的类型(子类Q,而非字面上的声明cdQ?、支持类型参敎ͼ也即是说Q以cd传递给该函数时Q就q回相应的类型信息对象?br />
说得具体一点,我们要求的反库是这样子的。当Ӟ首先要有一个类型信息对象TypeInfoQ里面装满了关于对于cd的所有详l信息。如下所C:可以猜到q种反射下框Ӟ只支持单l承Q这是故意的?br />
    struct TypeInfo
    {
    
public:
        template
<typename Args>
        
void ConstructObject(void* obj, MemoryAllocator* alloc, Args&& args)constQ?br />        bool IsDerviedOf(const TypeInfo* base)const;

    
public:
        
virtual TIType GetTIType()const = 0;
        
virtual const InterfaceMap* GetInterfaces()constQ?br />        virtual jushort GetMemorySize()constQ?br />        virtual ConstText GetName() constQ?br />        virtual AString GetFullName()constQ?br />        virtual jushort GetAlignSize() constQ?br />        virtual ConstText GetSpaceName()const;
        
virtual const TypeInfo* GetBaseTypeTI()const;
        
virtual const TypeInfo* GetPointeedTI()constQ?br />        virtual size_t GetHashCode(const void* obj)const;
        
virtual bool IsValueType()const { return true; }
        
virtual bool IsClass()const { return true; }

        
virtual bool DoInitAllocator(void* obj, MemoryAllocator* memAlloc)const;
        
virtual bool NeedDestruct()const { return false; }
        
virtual void DoDefaultConstruct(void* obj)const;
        
virtual bool CanDefaultConstruct()const { return true; }
        
virtual void DoAssign(void* dest, const void* src)const;
        
virtual bool Equals(const void* objA, const void* objB)const;
        
virtual void DoDestruct(void* obj)const;
        
    };
然后Q就要有一个函数TypeOfQ应该是两个Q一个是无参数的cd模板函数Q可以这栯用,TypeOf<type>()Q一个是有一个参数的cd模板函数Q可以这栯用,TypeOf(obj)。不是那一个,其返回结果都是const TypeInfo*。TypeOf的要做到的事情是Q对于每一U类型,有且只有一个唯一的TypeInfo对象与之对应Q不是template的还是非template的;比如Q以下的几个判断必须成立?br />TypeOf<int>() == TypeOf<int>();
TypeOf<int>() == TypeOf(n);    //n为整?br />TypeOf<vector<int>>() == TypeOf(nums);//nums的类型ؓvector<int>
Object* a = new ObjectA; TypeOf(a) == TypeOf<ObjectA>();
其实q里面的原理也没什么神奇,无非是trait配合sfineQ接下来全部都是苦力活Q就是ؓ每一U类型都专门特化一个详l描q的cd对象Q用宏可以节省大量的代码。但是整个反库Q本座前前后后重构了十几ơ,现在也还在重构之中,l究q是解决了开发上所遇到的各U事情。比如,序列化(支持指针、支持多态)、对象与xml的互换、对象与json的互换、数据库表读写对象、格式化、Anycd、非侵入式接口、消息发送、字W串生成对象{等?br />其实现方式,概括hQ就是引入间接层元函数TypeInfoImp专门用于q回一个类型typeQtype里面有一个GetTypeInfo()的函数。然后TypeOf调用TypeInfoImp里的type的GetTypeInfo()最l得到TypeInfo对象。代码如下所C?br />
    template<typename Ty> struct TypeInfoImp
    {
        typedef Ty type;
        
static const bool value = THasGetTypeInfoMethod<Ty>::value;
    };

    template
<typename Ty>
    
struct TypeInfoImp<const Ty> : public TypeInfoImp<Ty>
    {
        typedef typename TypeInfoImp
<Ty>::type type;
        
static const bool value = TypeInfoImp<Ty>::value;
    };
    
    template
<typename Ty>
    
const TypeInfo* TypeOf()
    {
        typedef typename TypeInfoImp
<Ty>::type TypeInfoProvider;
        
return TypeInfoProvider::GetTypeInfo();
    }
    
    template
<typename Ty>
    
const TypeInfo* TypeOf(const Ty& obj)
    {
        typedef typename IsRttiType
<Ty>::type is_rtti;    //又是间接层,对动态类型和非动态类型分别处?/span>
        return ImpTypeOf(obj, is_rtti());
    }
    
    template
<>
    
struct TypeInfoImp < bool >
    {
        
static const bool value = true;
        typedef TypeInfoImp
<bool> type;
        
static TypeInfo* GetTypeInfo();
    };
        
    TypeInfo
* TypeInfoImp<bool>::GetTypeInfo()
    {
        
static TypeInfo* ti = CreateNativeTypeInfo<bool>("bool");
        
return ti;
    }
可能可以有简z的方式Q比如不需要引入TypeInfoImpQ但是实际最l证明TypeInfoImp的方式最LzL也最能节省代码。最LQ它在自定义的struct或者class很方便Q只要改struct内部包含一个GetTypeInfo()的函敎ͼ它就可以被纳入TypeOf体系中,非常方便。对于模板类型的TypeInfoImpQ就要用到哈希表了。比如,对于std::paira的类型信息,如下实现Q?br />    template<typename FstTy, typename SndTy>
    struct TypeInfoImp < std::pair<FstTy, SndTy> >
    {
        static const bool value = true;
        typedef TypeInfoImp < std::pair<FstTy, SndTy> > type;
        static TypeInfo* GetTypeInfo()
        {
            ParamsTypeInfo<FstTy, SndTy> args;
            return PodPair::LookupTemplateTypeInfo(args);
        }
    };
提取其类型参数的const TypeInfo*Q生成数l。用此数l到PodPair的哈希表里面查找Q如果哈希表中以有此cd数组参数的对象就q回Q否则见创徏一个添加一条哈希条目,然后q回。每一个泛型类型,比如vectorQlistQpair都有一个属于自q哈希表?br />打完收工。原理很单,但是对于工业U的反射库,要考虑很多l节Q比如,TypeInfo对象的内存管理;怎么为enumcd生成一堆字W串Q以支持字符串和enume值的互相转换Q生成ƈ保存class的构造函数和析构函数指针Q命名空间的支持Q仿真C#里面的attributeQ如何以最方便的方式生成成员字D|者成员函C息等{,一句话Q就是他妈的体力zR但是,回报是很丰盛的,q里的苦力活做完之后Q程序的其他地方上,基本上,没有什么重复相似的代码Q一切的体力工作全部可以压在类型信息这里了?/div>

华夏之火 2017-07-05 11:45 发表评论
]]>
预处理之正整?/title><link>http://www.shnenglu.com/huaxiazhihuo/archive/2017/07/04/215050.html</link><dc:creator>华夏之火</dc:creator><author>华夏之火</author><pubDate>Tue, 04 Jul 2017 06:21:00 GMT</pubDate><guid>http://www.shnenglu.com/huaxiazhihuo/archive/2017/07/04/215050.html</guid><wfw:comment>http://www.shnenglu.com/huaxiazhihuo/comments/215050.html</wfw:comment><comments>http://www.shnenglu.com/huaxiazhihuo/archive/2017/07/04/215050.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/huaxiazhihuo/comments/commentRss/215050.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/huaxiazhihuo/services/trackbacks/215050.html</trackback:ping><description><![CDATA[<div>      虽然通过一pd的奇技淫yQ让预处理也囄完备一把,但是用预处理来做计算Q真的很吃力不讨好。因为预处理一开始设计出来的目的Q就没什么野心,原本׃仅只是ؓ了做单单的文本替换工作,q没有想q要成ؓ正儿八经的编E语aQ即便是最最~水版脚本语a的功能要求都达不到。只是后来,实在是大量要求要扚w自动生成代码Q特别是c++11之前的版本玩什么模板元~程Q铺天盖地的要有大量怼的代码。这些代码用其他工具来生成,当然形式会更加漂亮,但是始终q是用原生的预处理来做这U事情会更加的方便,否则每次修改Q都要运行一遍外部工P都麻烦啊Q本人是們֐于用预处理来生成代码的。另外,c++11之后Q的原来很多需要宏来生成代码的场合已经不必要了Q但是因为c++11的类型推D力大大加Z之后Q发现又有一大L地方可以用宏来生成代码了。ƈ不是说C++中的宏是必不可少之物Q但是用了宏Q真的可以减很多很多的重复代码Qv码纸面上的代码清爽了很多?nbsp;    <div>           </div>      预处理的原生数据cd只有符P然后W号只支?#的ƈ接运,同时Q预处理也能识别q接后的l果Q否则,q接q算没意义了)Q如果是宏函敎ͼp行调用操作,如果是宏W号Q就替换文本Q如果什么都不是Q就什么都不做Q保留符受但是这L弱鸡cdQ显然远q不能满离l叛道的码猿需要。经q大量的宏编E的试之后Q可以很肯定一点,预处理里面只能再模拟出来一U数据类型,那就是正整数Q虽焉过补码q算来仿真负敎ͼ但是׃预处理里面的W号不能包含减号(-)字符Q当然要花大力气捣鼓负整C是可以的Q只是用上也不方便也不直观Q性h比不高,基本上,必须用宏来生成代码的地方Q都可以不需要负整数的?br /><br /><div>     另外Q预处理也没有变量类型的概念Q不要说强类型,pq型也不是Q完全就是无cd。正整数cd的概念全靠码猿h肉编译器来维护,一个@环的宏代码生成一般都是来来回回也不知道调用了多少层宏调用QQ何一个地方出错,有时候是几吨密密麻麻的中间失败代码(~译器的预处理缓冲溢出,弃械投降Q,有时候就完全没有输出Q没有Q何一丁点的提C,直是大v捞针的找问题。因此,在用宏@环生成代码时Q必d心翼|步步Q不得不感慨Q正儿八l语a里面的类型真是好东西啊?/div><br />其实Q数据类型ƈ不重要,重要的是数据上能够支持的q算集合以及q些q算能运用的场合?br />好了Q回C文,我们用_ZPP_INC_N搞了10个数Q通过复制_脓Q可以把N增加?55。实际运用中Q完全够用了?br />#define _ZPP_INC_JOIN(_A, _B) _ZPP_INC_JOIN_IMP1(_A, _B)<br />#define _ZPP_INC_JOIN_IMP1(_A, _B) _ZPP_INC_JOIN_IMP2(~, _A##_B)<br />#define _ZPP_INC_JOIN_IMP2(p, res) res<br /><br />#define PP_INC(x, ) _ZPP_INC_JOIN(_ZPP_INC_, x)<br />#define _ZPP_INC_0         1<br />#define _ZPP_INC_1         2<br />#define _ZPP_INC_2         3<br />#define _ZPP_INC_3         4<br />#define _ZPP_INC_4         5<br />#define _ZPP_INC_5         6<br />#define _ZPP_INC_6         7<br />#define _ZPP_INC_7         8<br />#define _ZPP_INC_8         9<br />#define _ZPP_INC_9         10<br />...<br />#define _ZPP_INC_255       256<br /><br />同样的方式,再如法制PP_DECQ从256开始,一直递减?为止。对于大?56的数Q就不支持了Q那都是未定义操作。这样子Q通过PP_INC(n)Q就得到n+1Q而PP_DEC(n)Q则是n-1。比如PP_INC(PP_DEC(9))Q其l果肯定?了。很好,q样子,在预处理中就实现了自然数自增1和自?的运了。另外,对于大于256的数Q比?12传递给PP_INCQ就只得C个_ZPP_INC_512的符P完全没有M意义?br /><br />然后Q两个自然数是否相等的判断,也非帔R要,必须支持。但是,在此之前Q要实现一个宏函数PP_NOTQ用来判断入参是否ؓ0。ؓ0的话Q则函数q回1Q否则,p?。也xQ?br />PP_NOT(0) == 1<br />PP_NOT(23) == 0Q或?PP_NOT(var) == 0?br />CQ预处理提供l我们的原生cd只有符号和##q接q算Q除此之外,别无他物。好像工具太陋,能完成目的吗Q不得不佩服有些码猿的脑z。以下代码是q样q作的,假设PP_NOT生成以下的调用Ş式,先不PP_ARG1Q至于符号~Q是q样子的Q可以看成普通的变量名字Q它是占位W,因ؓ预处理只识别逗号(,)Q和括P至于其他W号Q完全无视,那些是C/C++~译阶段才关心的W号?br />PP_NOT(0) = PP_ARG1(~, 1, 0)<br />PP_NOT(n) = PP_ARG1(_ZPP_NOT_n, 0)<br />然后Q让PP_ARG1取第二个参数Q码猿的计数是从0开始的Q也xQ?x1Q?x2Q,完成Q务了。至于_ZPP_NOT_n是什么鬼Q那个只是中间生成的临时W号Q可以舍弃。我们只需对_ZPP_NOT_0做特别处理。因此,代码可以q样写了。PP_PROBE()用以生成两个入参<br />#define PP_PROBE() ~, 1<br />#define _ZPP_NOT_0 PP_PROBE()<br />#define PP_NOT(_X, ...) PP_IS(PP_JOIN(_ZPP_NOT_, _X))<br /># define PP_IS(...) PP_ARG1(__VA_ARGS__, 0)<br /><br />q样子之后,昄PP_NOT(n)可以变成PP_ARG1(_ZPP_NOT_n, 0)的Ş式了。PP_NOT不是只需一个入参吗Qؓ何后面还要带省略PUa是ؓ了后面各U变态的q用Q取悦编译器。已l用宏来写代码了Q就不必再遵守什么清规戒律,只要能完成Q务就行了?br /><br />至于PP_ARG1的实玎ͼ很单了Q如下所C,<br />#define PP_ARG0(_0, ...) _0<br />#define PP_ARG1(_0, _1, ...) _1<br />#define PP_ARG2(_0, _1, _2, ...) _2<br /><br />然后通过两次取反的函敎ͼ再补上函数PP_BOOLQ如果入?gt;0Q就q回1Q否则返?Q类g整型到bool的强制类型{换?br />#define PP_BOOL(_X, ...) PP_NOT(PP_NOT(_X))<br /><br />有了q些的铺垫之后,要比较两个自然数是否相等Q就单了。其实没什么神U的Q就是针对从0?55Q重?56个以下Ş式的#define语句Q?br />#define    _ZPP_0_EQUALS_0        PP_PROBE()<br />#define    _ZPP_1_EQUALS_1        PP_PROBE()<br />#define    _ZPP_2_EQUALS_2        PP_PROBE()<br />...<br />#define PP_EQUALS(x, y) PP_IS(PP_CONCAT4(_ZPP_, x, _EQUALS_, y))<br />PP_EQUALS是入参ƈ接成_ZPP_x_EQUALS_y的Ş式,只要x和y相同Q也x_它们在上面的表格中,那么Q道理就如同PP_NOT的实现那P最后结果就?了。其实,预处理中没有判断q种玩意Q只有表|只有q接Q只有查表。所谓的囄完备Q说白了Q没有玄虚的Q就是徏表,然后查表。对相等比较取反PP_NOTQ自然就得到不相{的判断函数?br />#define PP_UN_EQUALS(x, y) PP_NOT(PP_IS(PP_CONCAT4(_ZPP_, x, _EQUALS_, y)))<br />再次Q就可以得到boolq算的函敎ͼ或与<br />#define PP_OR(a,b) PP_CONCAT3(_ZPP_OR_, a, b)<br />#define _ZPP_OR_00 0<br />#define _ZPP_OR_01 1<br />#define _ZPP_OR_10 1<br />#define _ZPP_OR_11 1<br /><br />#define PP_AND(a,b) PP_CONCAT3(_ZPP_AND_, a, b)<br />#define _ZPP_AND_00 0<br />#define _ZPP_AND_01 0<br />#define _ZPP_AND_10 0<br />#define _ZPP_AND_11 1<br /><br />再准备一张表|字节映到8个二q制位?br />#define _ZPP_BINARY_0    (0, 0, 0, 0, 0, 0, 0, 0)<br />#define _ZPP_BINARY_1    (0, 0, 0, 0, 0, 0, 0, 1)<br />#define _ZPP_BINARY_2    (0, 0, 0, 0, 0, 0, 1, 0)<br />#define _ZPP_BINARY_3    (0, 0, 0, 0, 0, 0, 1, 1)<br />#define _ZPP_BINARY_4    (0, 0, 0, 0, 0, 1, 0, 0)<br />...<br />然后通过模拟计算机组成原理里面的加减乘除的原理,可以实现四则运了。对了,整个预处理库的代码都在压~包上,功能比boost的预处理库强多了Q但是代码却了很多Q也Ҏ理解多了Q所有代码在vs下面正常q行Q其他^台还没有试。代码包Q?a href="/Files/huaxiazhihuo/preprocessor.rar" style="color: #3366ff;">/Files/huaxiazhihuo/preprocessor.rar</a></div><img src ="http://www.shnenglu.com/huaxiazhihuo/aggbug/215050.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/huaxiazhihuo/" target="_blank">华夏之火</a> 2017-07-04 14:21 <a href="http://www.shnenglu.com/huaxiazhihuo/archive/2017/07/04/215050.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>预处理的囄完备之引ahttp://www.shnenglu.com/huaxiazhihuo/archive/2017/01/14/214594.html华夏之火华夏之火Sat, 14 Jan 2017 07:01:00 GMThttp://www.shnenglu.com/huaxiazhihuo/archive/2017/01/14/214594.htmlhttp://www.shnenglu.com/huaxiazhihuo/comments/214594.htmlhttp://www.shnenglu.com/huaxiazhihuo/archive/2017/01/14/214594.html#Feedback0http://www.shnenglu.com/huaxiazhihuo/comments/commentRss/214594.htmlhttp://www.shnenglu.com/huaxiazhihuo/services/trackbacks/214594.html好久没有光顾cppblog了,现在q里q么h了,不免让h有些伤感Q可见c++现在多么的不得h心,也可能是c++的大去了其他的|络q_Q好比知乎。不怎么P始终对c++q是有些感情Q也对cppblog有些感情?br />
我们q是来讨论c++吧,q几q在c++里面玩代码自动生成技术,而预处理是不可避免,也是不可或缺的重要工兗虽然boost pp预处理库在宏的运用上很是完善Q但是代码也太多了,而且代码很不好理解,ҎQ不免让人疑惑,有必要搞得那么复杂,搞那么多代码吗?q且Q看了boostpp的用接口后Q感觉写得很不干净Q也不好l合。因此,重新做了一套预处理的轮子。以下的代码Q假讑֜msvc2013以上的版本运行,反正很多人用MSVC的,装逼的自当别论Q造出来的轮子Q們֐于先支持msvc?br />
首先Q我们定义一个宏Q用来给把入参变成字W串Q咦Q这个事情也太easy了,但是Q在此,感觉Q还是有必要废话多解释一下。以下代码惯例都是,所有可用的宏函数都是以PP开头全部大写,而以_ZPP开头的全部都是内部实现Q其实还可以做得更难看一炏V因为宏函数是全局的,没有作用域的概念Qƈ且只是单U的文本替换Q死的时候,q不知道怎么死,所以,必须谨慎对待。像是windows.h头文仉P直接用minQmax作ؓ宏的名字Q虽然用h很方便,但也不知道制造了多少ȝQ所以,很多时候,包含windows.hӞW一件事情就是undef min和max?br />
以下的代码,可以随便在某个工E下Q随便徏立一个cpp后缀名的源文Ӟ然后按CTRL+F7~译Q不需要F5Q就可以看到q行的效果,如果~译通过Q就说明宏基本上正确Q测试代码越多,准确性就高。当Ӟ你们也可以通过讄源文件的属性,让msvc生成预处理后的文Ӟ然后用记事本打开那个文g观看?br />
#define PP_TEXT(str) _ZPP_TEXT(str)
#define _ZPP_TEXT(str) #str
在c++预处理宏中,操作W?是将后面跟随的表辑ּ加上两个双引P也就是字W串。PP_TEXT(str)不是直接定义?strQ而是通过调用_ZPP_TEXT(str)Q然后在那里才将入参变成字符Ԍ昑־有点辗{Q有点多此一举,但,其实是ؓ了支持宏的全方位展开Q也是入参str本n也存在宏调用的时候,U属无奈。比如,如果q样实现
#define PP_TEXT(str) #str
那么Q对于下面的情况Q?br />
#define AAA aaa
PP_TEXT(AAA)Q结果将?AAA",而不?aaa"。因为宏操作W直接是入参变成字W串Q没有让入参有一点点回旋的空_所以只好引入间接层Q让入参有机会宏展开。后面,很多宏函数都是这样实玎ͼ不得不间接调用,以便让宏全面展开。而msvc的宏展开机制更加奇葩Q更加不人性化Q其间接调用的Ş式也更丑陋。这都是没办法的事情?br />然后Qؓ了调试宏Q或者测试宏Q当Ӟ很多时候,调试宏,q是要打开预处理的文g来对比分析。我们对 static_assert作一点点包装Q因为static_assert需要两个参敎ͼc++11后面的c++版本中,static_assert好像只需要一个入参,那时׃需要这个包装了?br />
#define PP_ASSERT() static_assert((__VA_ARGS__), PP_TEXT(__VA_ARGS__));
PP_ASSERT(...)里面的三个点Q是不定参数的宏Q而__VA_ARGS__׃表了...所匚w的所有参敎ͼq条语法很重要,要熟l。这里,׃详细解释其用法了Q后面会有大把大把的宏函数用到__VA_ARGS__?br />好了Q我们可以开始用PP_ASSERT(...)做测试了?br />
PP_ASSERT(2+3==5)
如果Q然后编译这个文Ӟ发现~译通过了,比如
PP_ASSERT(2+3==4)
~译的时候,׃报错误信息,error C2338: 2+3==4
好了Q测试准备徏立v来,可以开始肆无忌惮的写代码了。一步一步地构徏c预处理宏的图灵完备?br />昄Q当务之急,最Ҏ的宏是两个宏参数的ƈ接,也即?#q算W,昄好比#q算那样子,必须l里面参数有宏展开的机会,因此要间接调用,下面是其实现
#define PP_JOIN(_A, _B) _ZPP_JOIN_I(_A, _B)
#define _ZPP_JOIN_I(_A, _B) _ZPP_JOIN_II(~, _A##_B)
#define _ZPP_JOIN_II(p, res) res
竟然不止一层间接,而是两层Q又多此一举,是因为发现在做宏递归的时候,一层间接调用还不能让宏充分地展开Q所以只好又加间接层Q也不明白是何原因,也懒得追I了。现在,接下来,当然是测试PP_JOIN了。各位同学,可以新徏立一个测试文Ӟ那个文ginclude我们的这个宏函数。当Ӟ也可以在同一个文仉面写试代码Q注意分成两D代码,上一D写宏函敎ͼ下一D写试代码Q目前来看,都可以的Q后面再整理?br />
PP_ASSERT(PP_JOIN(1+2== 3))
#define A 20
#define B 10
PP_ASSERT(PP_JOIN(A 
+ B, == 30))
有了PP_JOINQ就可以开始做点其他事情了。比如,计数器,
#define _ZPP_INC_JOIN(_A, _B) _ZPP_INC_JOIN_IMP1(_A, _B)
#define _ZPP_INC_JOIN_IMP1(_A, _B) _ZPP_INC_JOIN_IMP2(~, _A##_B)
#define _ZPP_INC_JOIN_IMP2(p, res) res

#define PP_INC(x, ) _ZPP_INC_JOIN(_ZPP_INC_, x)
#define _ZPP_INC_0         1
#define _ZPP_INC_1         2
#define _ZPP_INC_2         3
#define _ZPP_INC_3         4
#define _ZPP_INC_4         5
#define _ZPP_INC_5         6
#define _ZPP_INC_6         7
#define _ZPP_INC_7         8
#define _ZPP_INC_8         9
#define _ZPP_INC_9         10
q里Q我们重新又实现了一遍PP_JOINQ这也是没办法的事情Q后面在重重嵌套的时候,会出现PP_JOIN里面又包含PP_JOIN的情况,q样会导致宏停止展开了,所以,只好对于每一个要用到JOIN之处Q都用自q本的JOIN?br />q是宏函数的实现方式Q通过q接Q文本替换,一一枚DQ才辑ֈq样的效果,也就是说Q我们通过JOIN函数Q在宏里面构造了一个计数器的数据类型。如果每个宏函数都这样写Q岂不是很篏。好消息是,只需用这U苦逼方式实现几个最基本的函敎ͼ然后通过宏的递归引擎Q其他的宏函数就不需q样子一个一个苦逼的q接替换了?br />
PP_ASSERT(PP_INC(9)==10)
PP_ASSERT(PP_INC(PP_INC(
9)) == 11)
写测试代码习惯了Q写h很有意思了Q测试通过Q也是最Ȁ动h心的时刻?br />接下来,要处理msvc里面宏的恶心行ؓQ然后就l束本引a?br />
#define PAIR_SECOND(x, y) y
PP_ASSERT(PAIR_SECOND(
1020== 20)
q样子,q不错,下面Q再define一个宏函数Q让其返回一个pairQ也是两个?br />
#define MAKE_PAIR(x, y) x, y
然后Q这栯用,
PAIR_SECOND(MAKE_PAIR(1020))
~译器马上就不高兴了Qwarning C4003: “PAIR_SECOND”宏的实参不
好像是编译器没有先展开MAKE_PAIR(10, 20)Q然后再调用PAIR_SECONDQ而是直接把MAKE_PAIR(10, 20)整个当成一个函ClPAIR_SECONDQ然后,PAIR_SECOND提C实参不I然后Q硬要测试,
PP_ASSERT(PAIR_SECOND(MAKE_PAIR(1020)) == 20)
昄Q无论如何,~译器势必就龙颜大怒了。对此,我们只好再引入间接层Q想办法让MAKE_PAIR(10, 20)先展开Q然后再传给PAIR_SECOND。这P׃能直接用q样的Ş式了QPAIR_SECOND(MAKE_PAIR(10, 20)) 。只好改成这P下面的几行代码,很有Ҏ天地泣鬼的味道?br />
#define _ZPP_INVOKE_JOIN(_A, _B) _ZPP_IMP_INVOKE_JOIN_I(_A, _B)
#define _ZPP_IMP_INVOKE_JOIN_I(_A, _B) _ZPP_IMP_INVOKE_JOIN_II(~, _A##_B)
#define _ZPP_IMP_INVOKE_JOIN_II(p, res) res

#define PP_INVOKE(m, args, ) _ZPP_INVOKE_JOIN(m, args)
前面几行代码都是PP_INVOKE的JOIN函数实现Q可以直接当它们是JOIN函数Q关键是PP_INVOKE(m, args, ...)q里Q第一个参数m是宏函数Q第二个是argsQ是要传l第一个参数m的参数列表,用括hhQ至于后面的省略P是有些时候ؓ了取悦编译器而添加的Q也不知道是什么原因,反正q样子就可以了,懒得q究。垃圑֮Q垃N处理Q只要能完成功能p了,c++中,代码生成代码Q重头戏在tmp那里Q宏只是小必要的辅助工兯已。然后,q样调用Q?br />PP_ASSERT(PP_INVOKE(PAIR_SECOND, (MAKE_PAIR(10, 20))) == 20)
~译通过了,好不Ҏ啊!

华夏之火 2017-01-14 15:01 发表评论
]]>
ݺɫþþһ| 97þùۺϾƷŮ| ձþþþĻ| þþþ99ƷƬŷ| þۺϺݺۺϾþü | һaƬþëƬ16| ݺɫþۺ| þþƷ5555| ޾Ʒþǧն| ھƷþþþù| ˾þۺϳ| 99þ99þþƷƬ| ձɫվWWWþ | þþþþҹƷƷ| ձƷһþþ| ĻþþƷ| þþþavëƬ| ˾þü91| AVþ| ޾Ʒtvþþþþþþþ| þ99Ʒþþþþ벥 | þþƷŷպ| MM131޹Ůþ| þóСƵ| Ļþһ| 99ȳ˾ƷѾþ| Vþþ| þþþ99ƷƬŷ| 볬鱬Ļþ| avԾþþþa| þþþùպƷվ| ƷþĻ| þŷձƷ| þùƷ| 칫ҾþþƷ| 鶹ŷۺϾþ | þó18վ| þþƷ| žžþþƷר| þþþùɫAVѿͼƬ| þˬ˸߳AV|