基于C++11的call wrapper
要在C++中应用AOP,不像在其他的基于解释器的语言中那么方便,作为一种静态语言,如果给函数或者类的方法造一个wrapper,在wrapper里面嵌入调用前的代码和调用后的代码,也能达到一定程度的代码织入的效果。在C++11之前,要给一个函数或者方法做个能返回调用结果的wrapper并不简单,会比较复杂,而在C++11里面可以使用function模版,以及函数返回类型的推定,通过生成一个内嵌类的对象的构造函数来执行before动作,析构函数来实现after动作,而具体的before和action动作则可以通过lambda或者函数来表示,这样子实现起来就容易很多了,而且还可以设定一个对象给before/after动作作参数。
先看看函数的wrapper:
template<typename T, typename Probe>
struct Wrapper<T*, Probe>{
typedef function<void(Probe)> WrapFuncType;
T* _func;
Probe _probe;
WrapFuncType _after,
_before;
struct WrapInternal{
Wrapper<T*, Probe>* _wrapper;
WrapInternal(Wrapper<T*,Probe>* w) : _wrapper(w){
_wrapper->_before( _wrapper->_probe );
}
~WrapInternal(){
_wrapper->_after( _wrapper->_probe );
}
};
Wrapper(T* func,
Probe p,
WrapFuncType callBefore = [](Probe p){},
WrapFuncType callAfter = [](Probe p){}) : _probe(p){
_func = func;
_after = callAfter;
_before = callBefore;
}
template<typename ...Args>
auto operator()(Args && ...args)
->decltype( (*_func)(args...) ){
WrapInternal _w(this);
return (*_func)(args...);
}
};
这个 wrapper 能够包裹一个函数,生成的对象的调用也像原来的函数的调用一样调用:
int foo_int(int a) {
cout << "foo_int: " << a << endl;
return a * a;
}
typedef Wrapper<int(*)(int), int> T1;
T1 w4(&foo_int, 100,
[](int v){ cout << "w4<100> before" << endl; },
[](int v){ cout << "w4<100> after" << endl; });
cout << w4(400) << endl;
如果要给一个类方法做个wrapper,则可以按照如下方法:
template<typename T, typename Object, typename Probe>
struct Wrapper<T, Object, Probe>{
typedef function<void(Probe)> WrapFuncType;
T _method;
Object _obj;
Probe _probe;
WrapFuncType _after,
_before;
struct WrapInternal{
Wrapper<T, Object, Probe>* _wrapper;
WrapInternal(Wrapper<T, Object, Probe>* w) : _wrapper(w){
_wrapper->_before( _wrapper->_probe );
}
~WrapInternal(){
_wrapper->_after( _wrapper->_probe );
}
};
Wrapper(T&& method,
Object&& obj,
Probe p,
WrapFuncType callBefore = [](Probe p){},
WrapFuncType callAfter = [](Probe p){} ) : _probe(p){
_method = method;
_obj = obj;
_after = callAfter;
_before = callBefore;
}
template<typename ...Args>
auto operator()(Args && ...args)
->decltype(bind(_method, _obj, args...)(args...)) {
WrapInternal _w( this );
auto b = bind(_method, _obj, args...);
return b(args...);
}
};
使用的时候,设置好类名、对象、和方法:
struct Foo{
Foo(){
cout << "Foo::Foo" << endl;
}
void bar(int v){
cout << "Foo::bar " << v << endl;
}
};
typedef Wrapper<void(Foo::*)(int), Foo*, const char*> T2;
Foo f;
T2 w5(&Foo::bar, &f, "method",
[](const char* v){ cout << "w5<method> before" << endl;},
[](const char* v){ cout << "w5<method> after" << endl;});
w5(500);
通过这2种方法生成的wrapper对象还可以当作函数一样再次套上一个wrapper,也就是通过这种方法可以实现多个层次嵌套的wrapper,调用的时候从外到里的次序调用before动作,执行完原函数或者方法之后,再按照从里到外的次序调用after动作,最后返回原函数或者方法的返回值。
访问 https://github.com/icandroid/wrapper11 可以查看这个 wrapper 的源代码和演示例子。
基于C++11的call wrapper的更多相关文章
- 基于C++11实现线程池的工作原理
目录 基于C++11实现线程池的工作原理. 简介 线程池的组成 1.线程池管理器 2.工作线程 3.任务接口, 4.任务队列 线程池工作的四种情况. 1.主程序当前没有任务要执行,线程池中的任务队列为 ...
- 基于C++11的100行实现简单线程池
基于C++11的100行实现简单线程池 1 线程池原理 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小, ...
- 【C++11应用】基于C++11及std::thread实现的线程池
目录 基于C++11及std::thread实现的线程池 基于C++11及std::thread实现的线程池 线程池源码: #pragma once #include <functional&g ...
- 基于C++11的线程池实现
1.线程池 1.1 线程池是什么? 一种线程管理方式. 1.2 为什么用线程池? 线程的创建和销毁都需要消耗系统开销,当线程数量过多,系统开销过大,就会影响缓存局部性和整体性能.而线程池能够在充分利用 ...
- 基于C++11的数据库连接池实现
0.注意 该篇文章为了让大家尽快看到效果,代码放置比较靠前,看代码前务必看下第4部分的基础知识. 1.数据库连接池 1.1 是什么? 数据库连接池负责分配.管理和释放数据库连接,属于池化机制的一种,类 ...
- 基于c++11新标准开发一个支持多线程高并发的网络库
背景 新的c++11标准出后,c++语法得到了非常多的扩展,比起以往不论什么时候都要灵活和高效,提高了程序编码的效率,为软件开发者节省了不少的时间. 之前我也写过基于ACE的网络server框架,但A ...
- 基于C++11的线程池,简洁且可以带任意多的参数
咳咳.C++11 加入了线程库,从此告别了标准库不支持并发的历史.然而 c++ 对于多线程的支持还是比较低级,稍微高级一点的用法都需要自己去实现,譬如线程池.信号量等.线程池(thread pool) ...
- Dojo初探之4:dojo的event(鼠标/键盘)事件绑定操作(基于dojo1.11.2版本)
前言: 上一章详解了dojo的dom/query操作,本章基于dom/query基础上进行事件绑定操作 dojo的事件 dojo的事件绑定操作分为鼠标和键盘两种进行详解 1.鼠标事件 我们沿用上一章中 ...
- Dojo初探之3:dojo的DOM操作、query操作和domConstruct元素位置操作(基于dojo1.11.2版本)
前言: 前面两章讲了dojo的基本规范和配置,当然这个配置不是必须的,当你有这需求的时候就可以用到dojo的config配置. dojo的所有js都是符合AMD规范进行异步加载的:http://blo ...
随机推荐
- Python代码分析工具
Python代码分析工具:PyChecker.Pylint - CSDN博客 https://blog.csdn.net/permike/article/details/51026156
- 【Linux 内核网络协议栈源码剖析】网络栈主要结构介绍(socket、sock、sk_buff,etc)
原文:http://blog.csdn.net/wenqian1991/article/details/46700177 通过前面的分析,可以发现,网络协议栈中的数据处理,都是基于各类结构体,所有有关 ...
- 基于TCP的字符串传输程序
---恢复内容开始--- LINUX中的网络编程是通过SOCKET接口来进行的. Socket(套接字) Socket相当于进行网络通信两端的插座,只要对方的Socket和自己的Socket有通信联接 ...
- add environment path to powershell
https://4sysops.com/archives/use-powershell-to-execute-an-exe/ https://stackoverflow.com/questions/7 ...
- YTU 2896: J--Zipper
2896: J--Zipper 时间限制: 1 Sec 内存限制: 128 MB 提交: 29 解决: 15 题目描述 Given three strings, you are to determ ...
- 【Selenium】软件测试基础(软件测试分类和工具组)firebug、firepath的安装
白盒测试:需要了解内部结构和代码 黑盒测试:不关心内部结构和代码 灰盒测试:介于白盒黑盒之间 静态测试:测试时不执行被测试软件 动态测试:测试时执行被测试软件 单元测试:测试软件的单元模块 集成测试: ...
- 【BZOJ 2456】 mode
[题目链接] 点击打开链接 [算法] 此题初看是大水题,只需调用std :: sort即可 但是,n最大500000,显然会超时 而且,内存限制1MB,我们连数组也开不了! 那怎么做呢 ? 我们发现, ...
- java.lang.NoSuchMethodError: org.springframework.web.context.ConfigurableWebApplicationContext.setId
运行spring报了这个错误,网上说是spring版本冲突,检查maven依赖,发现我依赖的是spring-core.3.0.5,但是spring-orm和spring-tx依赖了spring-bea ...
- U3D中碰撞体和刚体的关系
1.刚体是用来接受力作用的组件: 2.碰撞体是碰撞系统用来检测碰撞的组件: 碰撞产生碰撞信息,游戏物体根据碰撞信息生成一个力作用在刚体上,刚体受力后就会产生一个速率,最终在游戏物体的运动体现出来. 也 ...
- [App Store Connect帮助]八、维护您的 App(3)将 App 恢复至 App Store
如果您已将 App 从 App Store 中移除,之后创建了该 App 的一个新版本,那么即使新版本被“App 审核”批准,App 状态也仍会是“被开发者下架”.若要发布新版本,您必须首先将其恢复至 ...