宏元编程——技术——解决重入引起展开失败问题

来源:互联网 发布:python 2.7 安装 编辑:程序博客网 时间:2024/06/05 07:17

什么是宏重入?

宏在展开的时候,如果遇到同名的宏会终止展开,把同名的宏当成一个整体。

#define MY_CAT(p1,p2) MY_CAT_D(p1,p2)#define MY_CAT_D(p1,p2) p1##p2#define MY_NIL#define AB(p1,p2) MY_CAT(p1,p2)1,MY_CAT(A, B(x, y))     =>MY_CAT(x,y)2,MY_CAT(AB(x,y),MY_NIL) =>xy
第2个不叫宏重入,叫“参数宏”,宏的参数是另外一个宏。这种情况下可以得到正确的展开结果xy。另外,这个地方为什么要定义MY_CAT_D?主要原因是MY_CAT在展开p1和p2的时候如果遇到##符号会停止展开,所以通过MY_CAT_D这个中间层可以使p1和p2先被展开然后再连接。

1在展开最外层MY_CAT之后,继续展开又会遇到MY_CAT,所以导致展开失败。

解决思路:通过定义相同功能不同名称的宏


方式1:定义AB的时候hardcode了一个可用的宏

#define MY_CAT1(p1,p2) MY_CAT1_D(p1,p2)#define MY_CAT1_D(p1,p2) p1##p2#define MY_CAT2(p1,p2) MY_CAT2_D(p1,p2)#define MY_CAT2_D(p1,p2) p1##p2#define MY_NIL#define AB(p1,p2) MY_CAT2(p1,p2)1,MY_CAT1(A, B(x, y)) =>xy

方式2:外层宏告诉内层宏使用相同功能可用的下一个“序号”

#define MY_CAT1(p1,p2) MY_CAT1_D(p1,p2)#define MY_CAT1_D(p1,p2) p1##p2#define MY_CAT2(p1,p2) MY_CAT2_D(p1,p2)#define MY_CAT2_D(p1,p2) p1##p2#define AB_D(d,p1,p2) MY_CAT##d(p1,p2)MY_CAT1(A, B_D(2,x, y)) => xy

方式3:外层宏可以自动探测下一个可用宏

step1:定义一系列的MY_CAT_xxx宏

#define MY_CAT_1(p1,p2) MY_CAT_1_D(p1,p2)#define MY_CAT_1_D(p1,p2) p1##p2#define MY_CAT_2(p1,p2) MY_CAT_2_D(p1,p2)#define MY_CAT_2_D(p1,p2) p1##p2#define MY_CAT_3(p1,p2) MY_CAT_3_D(p1,p2)#define MY_CAT_3_D(p1,p2) p1##p2#define MY_CAT_4(p1,p2) MY_CAT_4_D(p1,p2)#define MY_CAT_4_D(p1,p2) p1##p2#define MY_CAT_5(p1,p2) MY_CAT_5_D(p1,p2)#define MY_CAT_5_D(p1,p2) p1##p2#define MY_CAT_6(p1,p2) MY_CAT_6_D(p1,p2)#define MY_CAT_6_D(p1,p2) p1##p2#define MY_CAT_7(p1,p2) MY_CAT_7_D(p1,p2)#define MY_CAT_7_D(p1,p2) p1##p2#define MY_CAT_8(p1,p2) MY_CAT_8_D(p1,p2)#define MY_CAT_8_D(p1,p2) p1##p2

step2:定义谓词宏

#define MY_CAT_P(n) MY_CAT(MY_CAT_CHECK_, MY_CAT_ ## n(MY_NIL, MY_NIL))
step3:根据谓词宏拼装的宏来定义结果宏
#define MY_CAT_CHECK_MY_NILMY_NIL 1#define MY_CAT_CHECK_MY_CAT_8(p1, p2) 0#define MY_CAT_CHECK_MY_CAT_7(p1, p2) 0#define MY_CAT_CHECK_MY_CAT_6(p1, p2) 0#define MY_CAT_CHECK_MY_CAT_5(p1, p2) 0#define MY_CAT_CHECK_MY_CAT_4(p1, p2) 0#define MY_CAT_CHECK_MY_CAT_3(p1, p2) 0#define MY_CAT_CHECK_MY_CAT_2(p1, p2) 0#define MY_CAT_CHECK_MY_CAT_1(p1, p2) 0

说明:举例,如果MY_CAT_xxx不可用(未定义或已经被外层使用),MY_CAT_P的返回结果是MY_CAT_CHECK_MY_CAT_xxx(MY_NILL,MY_NIL)。我们可以把这个系列都定义成0。如果MY_CAT_xxx可用,MY_CAT_P返回值是MY_CAT_CHECK_MY_NILMY_NIL,把它定义成1.

step4:定义探测宏

参看宏元编程——技术——auto_rec

step5:测试

//#define AB MY_CAT(MY_CAT_, TL_AUTO_REC(MY_CAT_P, 4))#define AB TL_AUTO_REC(MY_CAT_P, 8)MY_CAT_4(A, B(x, y)) =>5(x,y)MY_CAT_2(A, B(x, y)) =>3(x,y)MY_CAT_1(A, B(x, y)) =>2(x,y)
说明:这个地方故意把AB定义成TL_AUTO_REC(MY_CAT_P, 8),可以看到自动检测的可用的”序号“

0 0
原创粉丝点击