宏是非常强大好用的工具。
基本上跨平台的类库,都是密密麻麻的宏。同时宏也常用于自动生成代码。
不过宏的语法有一定的局限性。
先从简单的宏看起:
从语法上来看,就是做个映射:
tag -> *
tag(x) -> *x*
但是我们做不到映射tag的一部分:
例如:
// MyCoutHelloWorld -> 错误
另外,tag的字符集合是[字母数字-_]。
这里推导出:任何含有“.”的代码段都至少含有两个tag,并且tag之间无法感知。
这会导致一些困难,举个常见的例子:
log类通常要打出行号(类似的,通常也要打出文件名),行号是一个预定义的宏:__LINE__。
我们希望保持代码简洁,也就是说期望打log的时候,不用传递行号(文件名)。例如:
注意到chatlog.info中间有一个点,根据前面的推论,这肯定是两个tag,并且不能相互感知。
1. 最简单的办法自然是映射info这个tag,如
但是这么做不大好,因为info这个tag太常见了,很容易就和别人的代码冲突了。
2. 另一种办法是定义一个不常见的tag,如myInfo(或者info__),这样代码就变成
这样也不太好,因为1. myInfo不存在于logger类里,这会让人很困惑;2. myInfo这个名字不自然,怪怪的。
3. 看来对info这个tag不能做映射。
来看看chatlog这个tag。这个tag通常是被定制的,既然是被定制的,就意味着进行映射是不会有冲突问题的。
这个tag可以得到__LINE__这些变量(也可以得到__FILE__等)。问题是需要把这些变量传递给info这个tag。
不管形式看起来怎么样,每个tag最后的值都是一个对象(或者变量)。info的值只能是函数,chatlog最后的值一定是一个logger对象(因为info是logger里的函数,也因为有‘.’号)。
问题转换成:如何把一个对象obj1知道的变量在fun1函数传给fun2函数?很简单,先把变量存起来,然后在fun1函数里,调用fun2函数。
最直接的做法,就是把__LINE__这些变量保存到logger对象里。
可以这么做:
看起来效果还不错,性能也可以接受。
不过还有改进的余地,明显strFilePath和strLine不应该属于logger类的。
既然不属于logger类,chatlog最后的值又必须是logger类,那么就放到一个logger的wrapper类里吧。。。
可以这么做:
当然还能再改进,懒得写了。
那一天要能支持正则表示的宏,那就太完美了。