在日常开发测试中,偶尔会有这样的需求,在一个cpp文件中,定义一些函数,而这些函数会在一定条件下被自动调用。
例如,我是在刷leetcode
题的时候,遇到了超时的问题,于是乎想写几个benchmark
函数测试一下性能。可是如果以后每次测性能都要重新写一遍的话,又很麻烦。于是乎,我有了这样一个需求:
1 | // leetXX.cpp |
如果普通的调用这个程序的话,这些MY_BENCH
函数不会被调用。
当我以
1 | ./leetXX bench 100 ... |
的形式运行时,这些bench
函数就会以参数中的循环次数运行并被统计运行时间:
1 | bench1 loop 100 times, cost XXXms. |
编写宏
不像java
,有万能的反射。首先想到的办法是,像go
一样,在包的init
中,把实现注册到一个全局的插槽中,这样别的项目只需要import
这个包,它的实现就会被自动使用。c++里会自动运行的函数果然还是变量定义时的构造函数。
所以,首先可以写出基础的类型定义和插槽:
1 | struct _bench_base_t |
然后,在一个统一的地方进行调用:
1 | void do_bench(_bench_base_t* bench, int loop) |
最后则是关键的宏定义:
1 |
LEET_BENCH
宏定义了一个派生类及实例,并在构造函数中把自己注册到全局的插槽中。
之后只要接函数体,就大功告成:
1 | // in leetXX.cpp |
需要注意的是,宏不能替换字符串中的内容,所以这里使用#fn
的方式拿到替换后的fn
的内容。