如何实现重复调用一个函数,非循环
在很多时候我们会有这么一个需求——
#define DUP_CALL(func, param, nTimes)
比如我调用:
DUP_CALL(puts, "Hello, world!", 3);
编译器将会自动生成——
puts("Hello, world!");
puts("Hello, world!");
puts("Hello, world!");
那么我们如何来实现这个需求呢?第一种方法可以使用宏,将宏迭代定义来展开调用次数。
而我这里将使用更高级的C++的泛型机制来解决这个问题。如果我们已经有支持C++0x的编译器,那么可以用以下代码:
1 #include <stdio.h>
2
3 template <typename RET_TYPE, typename PARAM_TYPE, RET_TYPE FUNC(PARAM_TYPE), unsigned N>
4 struct DupStruct
5 {
6 static inline void DupOpCall(PARAM_TYPE param)
7 {
8 DupStruct<RET_TYPE, PARAM_TYPE, FUNC, N -1>::DupOpCall(param);
9
10 FUNC(param);
11 }
12 };
13
14 template <typename RET_TYPE, typename PARAM_TYPE, RET_TYPE FUNC(PARAM_TYPE)>
15 struct DupStruct<RET_TYPE, PARAM_TYPE, FUNC, 0>
16 {
17 static inline void DupOpCall(PARAM_TYPE param)
18 {
19
20 }
21 };
22
23 #define DUP_CALL(func, param, nTimes) DupStruct<decltype(func(param)), decltype(param), func, nTimes>::DupOpCall(param)
24
25 int main(void)
26 {
27 DUP_CALL(puts, (constchar*)"Hello, world!", 3);
28 }
上面这段代码是在VC2010 Express Edition上编写的,在Release模式下编译后产生的汇编代码如下:
1 int main(void)
2 {
3 00401000push esi
4 DUP_CALL(puts, (const char*)"Hello, world!", 3);
5 00401001mov esi,dword ptr [__imp__puts (4020A0h)]
6 00401007push offset string "Hello, world!" (4020F4h)
7 0040100Ccall esi
8 0040100Epush offset string "Hello, world!" (4020F4h)
9 00401013call esi
10 00401015push offset string "Hello, world!" (4020F4h)
11 0040101Acall esi
12 0040101Cadd esp,0Ch
13 }
14 0040101Fxor eax,eax
15 00401021pop esi
16 00401022ret
如果我们使用GCC或与其兼容的编译器,那么我们可以使用typeof关键字——
#include <stdio.h>
template <typename RET_TYPE, typename PARAM_TYPE, RET_TYPE FUNC(PARAM_TYPE), unsigned N>
struct DupStruct
{
static inline void DupOpCall(PARAM_TYPE param)
{
DupStruct<RET_TYPE, PARAM_TYPE, FUNC, N -1>::DupOpCall(param);
FUNC(param);
}
};
template <typename RET_TYPE, typename PARAM_TYPE, RET_TYPE FUNC(PARAM_TYPE)>
struct DupStruct<RET_TYPE, PARAM_TYPE, FUNC, 0>
{
static inline void DupOpCall(PARAM_TYPE param)
{
}
};
#define DUP_CALL(func, param, nTimes) DupStruct<typeof(func(param)), typeof(param), func, nTimes>::DupOpCall(param)
extern"C"void cpp_test(void)
{
DUP_CALL(puts, "Hello, world!", 3);
}
我们会发现decltype完整地保留了对象的完整的类型,由于const char[14]作为形参类型会自动弱化为const char*,因此会与模板实参类型产生冲突。而typeof修饰字符串将自动获得const char*类型,因此我们会看到typeof版本不需要对字符串做强转。