C++11 函数装饰器
在pyhon里经常看到如下的代码
def Decorator(func):
def _func(*args, **kwargs):
print("before function")
result = func(*args, **kwargs)
print("after function")
return result
return _func
@Decorator
def func_a(a, b):
print(a + b)
if __name__ == '__main__':
func_a(1, 4)
运行上述代码,可以看到如下的结果
before function 5 after function
利用装饰器,我们可以实现函数计时、授权检查、日志等等复杂的功能。 那么如何在C++里实现一个类似的功能呢? 我们可以利用函数指针的功能,将函数暂存在装饰器类中,然后再调用前与调用后执行相应的功能。 话不多说直接上代码
template<typename FUN_RET_TYPE, typename ... FUN_ARGS>
class Decorator {
protected:
std::function<FUN_RET_TYPE(FUN_ARGS...)> decorated_func;
public:
explicit Decorator(const std::function<FUN_RET_TYPE(FUN_ARGS...)> &p_func) {
decorated_func = p_func;
}
explicit Decorator(FUN_RET_TYPE(*p_func)(FUN_ARGS...)) :
Decorator(std::function<FUN_RET_TYPE(FUN_ARGS...)>(p_func)) {
}
virtual FUN_RET_TYPE operator()(FUN_ARGS...args) = 0;
};
这样我们就做好了一个简单的装饰器类,接下来我们将上面的python代码移植进来
template<typename FUN_RET_TYPE, typename ... FUN_ARGS>
class FuncTimer : public Decorator<FUN_RET_TYPE, FUN_ARGS...> {
private:
std::string tip_str;
public:
explicit FuncTimer(const std::function<FUN_RET_TYPE(FUN_ARGS...)> &p_func, std::string tip_str = "")
: Decorator<FUN_RET_TYPE, FUN_ARGS...>(p_func), tip_str(std::move(tip_str)) {
}
explicit FuncTimer(FUN_RET_TYPE(*p_func)(FUN_ARGS...), std::string tip_str = "")
: Decorator<FUN_RET_TYPE, FUN_ARGS...>(p_func), tip_str(std::move(tip_str)) {
}
FUN_RET_TYPE operator()(FUN_ARGS...args) override {
auto before = std::chrono::system_clock::now().time_since_epoch().count();
FUN_RET_TYPE result = this->decorated_func(args...);
auto after = std::chrono::system_clock::now().time_since_epoch().count();
std::cout << tip_str << after - before << std::endl;
return result;
}
};
这里实现了一个简单的计时器装饰器,传入一个字符串用于控制打印的字符。 这里的装饰器有一个比较难以操作的问题:如果函数返回值为void,那么在模板替换的时候就会出现void result = this->decorated_func(args...); 这段代码会直接报编译错误,因为C++并没有void型变量。相比C++而言,上面的那段python代码不会出错,因为python在处理无返回值函数时默认返回None ,因此将None 赋值给result 不会出错。解决C++ void函数装饰问题可以简单的使用有返回值的lambda函数进行二次包装。这里直接使用宏定义的形式,如下:
#define CalFuncExecTime(content, text) FuncTimer<void *, void *>([&](void *_) -> void * {\
do{content}while(false);\
return nullptr;\
}, text)(nullptr)\
这里定义了返回值为void * 的lambda函数,用装饰器包装了它,避免出错。同时这个宏还可以用来包装一段代码块。 下面是测试代码
class A {
public:
int x;
explicit A(int x) : x(x) {}
int test(int a, int b) const {
return a + b + x;
}
};
int main() {
FuncTimer<int, int, int> timer1(test, "timer1 : ");
cout << timer1(2, 4) << std::endl;
CalFuncExecTime(A a(6);
a.test(1, 4);,
"A : "
);
}
输出:
timer1 : 5 6 A : 5
|