1 #define BOOL(n) BOOL##n 2 #define BOOL0 0 3 #define BOOL1 1 4 #define BOOL2 1 5 #define BOOL3 1
BOOL(n)可獲取值n的真假值
1 #define IF(c, x, y) IF##c(x, y) 2 #define IF0(x, y) y 3 #define IF1(x, y) x
上面的宏是想要實現選擇控制,IF中傳入邏輯值c,若c為0則返回y, 若c為1則返回x
假如按如下調用: IF( BOOL(3), "t", "f" ),按直覺此句應生成“t”, 可事與願違, 因為展開BOOL(3)時碰到##,所以直接返回BOOL3, 結果上面的宏就變成了 IF( BOOL3, "t", "f"),按IF宏體繼續展開, 則變成了 IFBOOL3("t", "f") 最後預處理器報錯: 找不到IFBOOL3 因此,為了能正確地把參數BOOL(3)展開為1,還需要多包裝多一層宏:1 #define IF(c, x, y) IF_C(c, x, y) 2 #define IF_C(c, x, y) IF##c(x, y)
這樣,IF( BOOL(3), "t", "f" )就會先展開參數,變成 IF( BOOL3, "t", "f"),
然後宏體展開, IF_C( BOOL3, "t", "f" ),展開參數成了, IF_C( 1, "t", "f" ), 最後才會正確地展開成 IF1( "t", "f" ) 4、缺少整數類型,若要利用計數器循環生成代碼時非常麻煩,首先要自己手工定義一堆整數的INC:1 #define INC_0 1 2 #define INC_1 2 3 #define INC_2 3 4 #define INC_3 4 5 …………… 6 7 #define DEC_x x 8 ………………
然後再在INC_xx和DEC_xx之上定義加法,減法, 這樣做相當於需要手工利用最基本的元素構造基本方法,再將這些基本方法不停地復合嵌套,抽象出更高階的函數, 工作量跟創造語言差不多 本來創造語言還是挺有趣的一件事,可由於剛剛提過的反人類反直覺的古怪傳參機制的存在, 致使復合方法構造高階函數的過程異常痛苦,得不時留意參數展開時會不會被#和##打斷,若被打斷則需要增加一層宏來繼續展開。 5、無法實現遞歸,如:
1 #define x y+1 2 #define y x+1
則展開x時,先展開成y+1,繼續展開y,x+1+1,這時又碰到了x,預處理器便停止展開了。
無法實現遞歸,那利用宏實現循環時就變得異常冗長了。 一般來說,while循環和尾遞歸是等價的,所以若支持遞歸,則可用尾遞歸的形式實現循環,但現在不支持, 所以我們需要把尾遞歸的每一步都得親自展開,並將其手工顯示的定義成宏,如:1 #define WHLE(...) WHILE##n(...) 2 #define WHILE0(...) xxxxx 3 #define WHLE1(....) WHILE0(......) 4 #define WHLE2(....) WHILE1(......) 5 #define WHLE3(....) WHILE2(......) 6 ...................
這樣做不僅麻煩,而且遞歸深度也只能是一個固定值 6、c的宏只是作簡單的文本替換,所以替換到文本後可能會出現,下面就是一個最經典的例子:
1 #define square(x) x*x 2 cout<<square(2+3)<<endl;
替換後就變成了2+3*2+3,所以寫宏時還要注意在必要的地方加括號。。。。。。。。。
7、沒辦法傳function-like macro的名字,如:1 #define ADD(n, m) .......... 2 #define FOR(k, op,...) ......
若調用FOR((3,3), ADD,...),想要在FOR內部ADD(3,3),發現預處理器會報錯,說ADD沒定義。
也就是說函數名不能當參數傳入,當然我發現boost裡面是可以的,估計是用了什麼奇技淫巧,沒耐性看,各位大神知道的話請指點以下。