青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

huaxiazhihuo

 

預處理的圖靈完備之引言

好久沒有光顧cppblog了,現在這里這么冷清了,不免讓人有些傷感,可見c++現在多么的不得人心,也可能是c++的大神去了其他的網絡平臺,好比知乎。不管怎么樣,始終對c++還是有些感情,也對cppblog有些感情。

我們還是來討論c++吧,這幾年在c++里面玩代碼自動生成技術,而預處理是不可避免,也是不可或缺的重要工具。雖然boost pp預處理庫在宏的運用上很是完善,但是代碼也太多了,而且代碼很不好理解,對此,不免讓人疑惑,有必要搞得那么復雜,搞那么多代碼嗎?并且,看了boostpp的使用接口后,感覺寫得很不干凈,也不好組合。因此,重新做了一套預處理的輪子。以下的代碼,假設在msvc2013以上的版本運行,反正很多人用MSVC的,裝逼的自當別論,造出來的輪子,傾向于先支持msvc。

首先,我們定義一個宏,用來給把入參變成字符串,咦,這個事情也太easy了,但是,在此,感覺,還是有必要廢話多解釋一下。以下代碼慣例都是,所有可用的宏函數都是以PP開頭全部大寫,而以_ZPP開頭的全部都是內部實現,其實還可以做得更難看一點。因為宏函數是全局的,沒有作用域的概念,并且只是單純的文本替換,死的時候,還不知道怎么死,所以,必須謹慎對待。像是windows.h頭文件那樣,直接用min,max作為宏的名字,雖然用起來很方便,但也不知道制造了多少麻煩,所以,很多時候,包含windows.h時,第一件事情就是undef min和max。

以下的代碼,可以隨便在某個工程下,隨便建立一個cpp后綴名的源文件,然后按CTRL+F7編譯,不需要F5,就可以看到運行的效果,如果編譯通過,就說明宏基本上正確,測試代碼越多,準確性就越高。當然,你們也可以通過設置源文件的屬性,讓msvc生成預處理后的文件,然后用記事本打開那個文件觀看。
#define PP_TEXT(str) _ZPP_TEXT(str)
#define _ZPP_TEXT(str) #str
在c++預處理宏中,操作符#是將后面跟隨的表達式加上兩個雙引號,也就是字符串。PP_TEXT(str)不是直接定義成#str,而是通過調用_ZPP_TEXT(str),然后在那里才將入參變成字符串,顯得有點輾轉,有點多此一舉,但,其實是為了支持宏的全方位展開,也就是入參str本身也存在宏調用的時候,純屬無奈。比如,如果這樣實現
#define PP_TEXT(str) #str
那么,對于下面的情況,
#define AAA aaa
PP_TEXT(AAA),結果將是"AAA",而不是"aaa"。因為宏操作符直接是將入參變成字符串,沒有讓入參有一點點回旋的空間,所以只好引入間接層,讓入參有機會宏展開。后面,很多宏函數都是這樣實現,不得不間接調用,以便讓宏全面展開。而msvc的宏展開機制更加奇葩,更加不人性化,其間接調用的形式也更丑陋。這都是沒辦法的事情。
然后,為了調試宏,或者測試宏,當然,很多時候,調試宏,還是要打開預處理的文件來對比分析。我們對 static_assert作一點點包裝,因為static_assert需要兩個參數,c++11后面的c++版本中,static_assert好像只需要一個入參,那時就不需要這個包裝了。
#define PP_ASSERT() static_assert((__VA_ARGS__), PP_TEXT(__VA_ARGS__));
PP_ASSERT(...)里面的三個點,是不定參數的宏,而__VA_ARGS__就代表了...所匹配的所有參數,這條語法很重要,要熟練。這里,就不詳細解釋其用法了,后面會有大把大把的宏函數用到__VA_ARGS__。
好了,我們可以開始用PP_ASSERT(...)做測試了。
PP_ASSERT(2+3==5)
如果,然后編譯這個文件,發現編譯通過了,比如
PP_ASSERT(2+3==4)
編譯的時候,就會報錯誤信息,error C2338: 2+3==4
好了,測試準備建立起來,就可以開始肆無忌憚的寫代碼了。一步一步地構建c預處理宏的圖靈完備。
顯然,當務之急,最根本的宏就是將兩個宏參數的并接,也即是##運算符,顯然好比#運算那樣子,必須給里面參數有宏展開的機會,因此要間接調用,下面是其實現
#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
竟然不止一層間接,而是兩層,又多此一舉,是因為發現在做宏遞歸的時候,一層間接調用還不能讓宏充分地展開,所以只好又加間接層,也不明白是何原因,也懶得追究了。現在,接下來,當然是測試PP_JOIN了。各位同學,可以新建立一個測試文件,那個文件include我們的這個宏函數。當然,也可以在同一個文件里面寫測試代碼,注意分成兩段代碼,上一段寫宏函數,下一段寫測試代碼,目前來看,都可以的,后面再整理。
PP_ASSERT(PP_JOIN(1+2== 3))
#define A 20
#define B 10
PP_ASSERT(PP_JOIN(A 
+ B, == 30))
有了PP_JOIN,就可以開始做點其他事情了。比如,計數器,
#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
這里,我們重新又實現了一遍PP_JOIN,這也是沒辦法的事情,后面在重重嵌套的時候,會出現PP_JOIN里面又包含PP_JOIN的情況,這樣會導致宏停止展開了,所以,只好對于每一個要用到JOIN之處,都用自己版本的JOIN。
這是宏函數的實現方式,通過并接,文本替換,一一枚舉,才達到這樣的效果,也就是說,我們通過JOIN函數,在宏里面構造了一個計數器的數據類型。如果每個宏函數都這樣寫,豈不是很累。好消息是,只需用這種苦逼方式實現幾個最基本的函數,然后通過宏的遞歸引擎,其他的宏函數就不需這樣子一個一個苦逼的并接替換了。
PP_ASSERT(PP_INC(9)==10)
PP_ASSERT(PP_INC(PP_INC(
9)) == 11)
寫測試代碼習慣了,寫起來就很有意思了,測試通過,也是最激動人心的時刻。
接下來,要處理msvc里面宏的惡心行為,然后就結束本引言。
#define PAIR_SECOND(x, y) y
PP_ASSERT(PAIR_SECOND(
1020== 20)
這樣子,還不錯,下面,再define一個宏函數,讓其返回一個pair,也就是兩個值
#define MAKE_PAIR(x, y) x, y
然后,這樣調用,
PAIR_SECOND(MAKE_PAIR(1020))
編譯器馬上就不高興了,warning C4003: “PAIR_SECOND”宏的實參不足
好像是編譯器沒有先展開MAKE_PAIR(10, 20),然后再調用PAIR_SECOND,而是直接把MAKE_PAIR(10, 20)整個當成一個函數傳給PAIR_SECOND,然后,PAIR_SECOND就提示實參不足,然后,硬要測試,
PP_ASSERT(PAIR_SECOND(MAKE_PAIR(1020)) == 20)
顯然,無論如何,編譯器勢必就龍顏大怒了。對此,我們只好再引入間接層,想辦法讓MAKE_PAIR(10, 20)先展開,然后再傳給PAIR_SECOND。這樣,就不能直接用這樣的形式了,PAIR_SECOND(MAKE_PAIR(10, 20)) 。只好改成這樣,下面的幾行代碼,很有點驚天地泣鬼神的味道。
#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函數實現,可以直接當它們是JOIN函數,關鍵是PP_INVOKE(m, args, ...)這里,第一個參數m是宏函數,第二個是args,是要傳給第一個參數m的參數列表,用括號括起來,至于后面的省略號,是有些時候為了取悅編譯器而添加的,也不知道是什么原因,反正這樣子就可以了,懶得追究。垃圾宏,垃圾預處理,只要能完成功能就行了,c++中,代碼生成代碼,重頭戲在tmp那里,宏只是小小必要的輔助工具而已。然后,這樣調用,
PP_ASSERT(PP_INVOKE(PAIR_SECOND, (MAKE_PAIR(10, 20))) == 20)
編譯通過了,好不容易啊!

posted on 2017-01-14 15:01 華夏之火 閱讀(1481) 評論(0)  編輯 收藏 引用 所屬分類: C++代碼自動生成

導航

統計

常用鏈接

留言簿(6)

隨筆分類

隨筆檔案

搜索

積分與排名

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲一区二区精品| 亚洲国产精品一区二区第四页av| 亚洲精品一区二区三区在线观看| 米奇777在线欧美播放| 久久久亚洲国产天美传媒修理工| 黄色日韩在线| 亚洲激情另类| 国产精品久久国产精品99gif| 午夜精品久久久久久久久| 性娇小13――14欧美| 在线精品视频一区二区三四| 欧美激情一区二区三级高清视频 | 欧美一级一区| 久久精品国产v日韩v亚洲| 亚洲人体影院| 亚洲欧美成aⅴ人在线观看| 精品成人一区二区三区| 亚洲人午夜精品免费| 国产欧美成人| 亚洲国产美女| 国产欧美在线观看| 亚洲国产成人精品久久久国产成人一区| 欧美日韩精品| 欧美阿v一级看视频| 欧美午夜久久久| 国产精品欧美激情| 亚洲成人在线观看视频| 亚洲精品中文字| 极品少妇一区二区| 一本久久综合亚洲鲁鲁五月天| 国产自产精品| 中文日韩在线视频| 亚洲精品日韩激情在线电影| 亚洲欧美成aⅴ人在线观看| 亚洲伦伦在线| 久久人人九九| 久久精品一区二区三区不卡牛牛| 欧美日本精品一区二区三区| 美女视频一区免费观看| 国产欧美日韩一区二区三区在线 | 一区二区三区免费看| 久久精品国产一区二区三区免费看| 一本色道久久加勒比88综合| 美日韩精品免费观看视频| 欧美一区二视频| 国产精品成人午夜| 亚洲理伦电影| 亚洲毛片播放| 欧美成人免费全部| 免费看的黄色欧美网站| 国产一区欧美日韩| 亚洲欧美视频在线| 香蕉成人啪国产精品视频综合网| 欧美日韩精品系列| 亚洲精品国产欧美| 一区二区国产日产| 欧美人与性动交α欧美精品济南到| 免费中文日韩| 亚洲高清不卡av| 六月婷婷一区| 亚洲人成网站在线播| 亚洲激情校园春色| 牛夜精品久久久久久久99黑人| 欧美11—12娇小xxxx| 在线精品亚洲一区二区| 美国成人直播| 亚洲人成网站999久久久综合| 亚洲国产美女| 欧美日韩伦理在线免费| 亚洲伦理久久| 性xx色xx综合久久久xx| 国产欧美va欧美不卡在线| 欧美一区观看| 欧美大片免费看| 亚洲美女啪啪| 国产精品久久国产三级国电话系列 | 亚洲欧美中文字幕| 国产乱码精品| 欧美一区二区在线免费观看| 久久综合久久综合这里只有精品| 在线成人av网站| 欧美精品色网| 亚洲中字在线| 麻豆精品一区二区综合av| 亚洲电影毛片| 欧美婷婷久久| 午夜在线观看免费一区| 欧美高清视频在线观看| 亚洲午夜影视影院在线观看| 欧美主播一区二区三区| 亚洲人成久久| 欧美日韩国产区| 欧美亚洲一区二区在线| 美女网站久久| 亚洲网站在线| 亚洲成色www8888| 国产精品第三页| 久久亚洲高清| 中文亚洲免费| 亚洲国产mv| 久久国产直播| 亚洲视频在线观看免费| 国户精品久久久久久久久久久不卡| 欧美成人精品影院| 久久精品国产在热久久 | 欧美成人中文字幕| 亚洲欧美中文在线视频| 亚洲人www| 国产资源精品在线观看| 欧美日韩国产一中文字不卡| 欧美在线亚洲| 宅男噜噜噜66一区二区66| 欧美电影专区| 久久久久国产精品一区二区| 亚洲亚洲精品在线观看 | 亚洲伊人伊色伊影伊综合网| 黄色日韩精品| 国产欧美韩国高清| 欧美色精品天天在线观看视频| 噜噜噜久久亚洲精品国产品小说| 亚洲天堂网在线观看| 亚洲黄色毛片| 亚洲二区在线观看| 欧美aaa级| 米奇777在线欧美播放| 久久精品二区| 欧美伊人久久大香线蕉综合69| 在线亚洲自拍| 99av国产精品欲麻豆| 亚洲欧洲精品一区二区精品久久久| 韩国三级电影一区二区| 国产欧美精品一区二区色综合| 欧美日韩在线一区二区| 欧美精品一区二区在线播放| 免费看的黄色欧美网站| 久久高清国产| 久久久av水蜜桃| 久久久久久久一区二区| 久久久xxx| 久久亚洲国产成人| 久久免费高清视频| 牛牛精品成人免费视频| 欧美a级片一区| 欧美大片网址| 欧美日韩国产不卡| 国产精品mv在线观看| 国产精品久久久久久久午夜 | 国产精品一区二区久激情瑜伽| 国产精品日韩欧美一区二区| 国产精品免费看久久久香蕉| 国产日本欧美一区二区三区在线 | 欧美精品久久久久久久免费观看 | 久久成人一区| 亚洲一区二区精品视频| 国产精品一区一区| 性欧美精品高清| 欧美日韩一区综合| 国产日韩精品电影| 国产欧美精品一区二区色综合| 欧美无砖砖区免费| 国产精品色在线| 国产一区二区精品久久99| 狠狠色综合日日| 亚洲日韩成人| 午夜精品久久久久久久白皮肤| 午夜欧美电影在线观看| 久久夜色精品国产亚洲aⅴ| 亚洲第一精品夜夜躁人人爽| 亚洲高清影视| 亚洲一区图片| 老鸭窝毛片一区二区三区| 欧美激情一区二区三区成人| 国产精品欧美一区二区三区奶水 | 永久域名在线精品| 亚洲日本在线视频观看| 午夜欧美大尺度福利影院在线看| 老牛嫩草一区二区三区日本| 亚洲激情午夜| 欧美一区二区三区免费在线看 | 亚洲精品国产精品久久清纯直播| 亚洲一区二区在| 欧美电影打屁股sp| 国产一区白浆| 亚洲天堂第二页| 欧美国产一区二区| 香蕉av福利精品导航| 欧美伦理在线观看| 影音先锋另类| 欧美一区精品| 日韩午夜在线观看视频| 蜜桃av一区二区在线观看| 国产精品色网| 亚洲一区观看| 亚洲精品一区二区三区av| 久久久精品免费视频| 国产精品无码永久免费888| 日韩亚洲欧美综合| 欧美电影免费网站| 久久国产毛片| 国产一区二区三区丝袜|