【1】用宏的技巧,查表法
查表法的作用是输入一个或多个参数,查表得到另一个参数,boost里面很多宏的实现都是查表法,例如
BOOST_PP_BOOL(x) 将整数x转换成0或1
BOOST_PP_INC(x) 将返回x+1
BOOST_PP_DEC(x)返回x-1
BOOST_PP_BITAND(x,y) 对两个bit进行与操作
BOOST_PP_BITNOR(x,y) 对两个bit进行或非操作
BOOST_PP_BITOR(x,y) 对两个bit进行或操作
BOOST_PP_BITXOR(x,y) 对两个bit进行异或操作
BOOST_PP_COMPL(x) 对一个bit进行取反操作
查表法的原理如下
#define MARCO_NAME(x) MARCO_NAME_I (x)
#define MARCO_NAME_I (x) MARCO_ ## x
#define MARCO_x y (这里不是一个宏,要定义一大堆的宏,对每一个可能的输入值x,将MARCO_x定义成要返回的值y)
为什么不省略宏MARCO_NAME_I,直接定义成 #define MARCO_NAME(x) MARCO_ ## x
回答这个问题,需要了解宏置换的具体过程(就像函数调用过程一样)。不同的书上有不同的解释,本人的解释如下:
调用一个带参数的宏时,要输入一堆的参数,编译其在置换宏前,对每个参数都触发置换过程,用一个表保存每个参数置换前的值和置换后的值。在置换宏时,如果对参数使用了#或##或#@运算符,那么替换成参数置换前的值;否则替换成参数置换后的值。
例如
#define N 100
#define M(a) a, #a
M(N);
在置换宏M前,得到一个参数列表
参数名=a,置换前的值=N,置换后的值=100
置换宏时,逗号前面的a被替换成100,#后面的a被替换成N
M(N)被置换成 100,"N"
VC++编译器没有遵循标准规定,将##运输符两边的参数替换成参数置换后的值。看似能节省代码,实际上遇到下面宏时就不知道怎么翻译了 #define M(a,b,c) # a ## b ## c,标准没有规定#和##运输符的优先级,也没有规定##运算符是左结合、还是右结合
【2】BOOST_PP_IF和BOOST_PP_IIF的本质也是查表法
上面的查表法都是输入一个常数,得到另一个常数,更高级的技巧是输入一个常数和一些变量,返回处理过的变量。
BOOST_PP_IIF的实现如下,bit允许输入0或1,t和f可以是任意形式的参数,甚至可以是另一个宏名
#define BOOST_PP_IIF(bit, t, f) BOOST_PP_IIF_I(bit, t, f)
#define BOOST_PP_IIF_I(bit, t, f) BOOST_PP_IIF_ ## bit(t, f)
#define BOOST_PP_IIF_0(t, f) f
#define BOOST_PP_IIF_1(t, f) t
【3】BOOST_PP_TUPLE_ELEM查的是一个二维表
该宏从一个tuple中获取特定位置的元素,相当于根据下标从数组中取元素。
BOOST_PP_TUPLE_ELEM(size, index, tuple)
参数size是一个整数,标明tuple的长度
参数index是下标,从0开始
参数tuple是类似(a,b,c,d)格式的结构
BOOST_PP_TUPLE_ELEM (4, 2, (a,b,c,d)) 返回结果是c