在C++中使用libuv时对回调的处理
新的解决方法
https://www.cnblogs.com/ink19/p/13768425.html
libuv简介
libuv是一个可以跨平台的C语言库,它提供了基于事件的异步IO支持[1]。提供了很多事件的支持,涉及到网络、文件、信号、线程、进程等。主要设计应用在Nodejs,也有很多其他知名的项目使用了这一库。
问题说明
libuv的易用性非常高(在我看来比boost.asio简单多了),如果用C来调用它的话,基本上没有什么问题。但是C++在构建大型项目上有着无可比拟的优异性。在我准备把我之前用C写的一个libuv程序[2]改成C++的时候,出现了一些问题。
问题在哪呢?如果有了解libuv的话,应该都知道在使用libuv的时候使用了大量的回调。如果使用C,那只要按照要求对每一个回调函数写一个相应的回调就好了,但是这种方法在C++里面并不优雅。我们更希望能够直接将回调函数写在类的内部,这样就可以直接对类的数据进行操作。为了实现这一想法,我很自然的依靠std::bind写出了一下的代码。
class A {
public:
void on_callback(uv_req_t *req);
};
int main() {
A a;
uv_fs_open(loop, req, path, flags, mode, std::bind(&A::on_callback, &a, _1));
return 0;
}
但是很遗憾编译错误。uv_fs_open需要的是一个函数指针,但是std::bind提供的并不是一个指针,它还包含了很多的东西。比如A类的实例a。这导致了它没办法转换成函数指针。
解决方法
那有没有可靠的解决方法呢?我在网上找了很多的资料,其中轮子哥的一个方法[3]好像可以解决这个问题,但是由于才疏学浅,并不能读到那篇博文。还有一种方法是C++ thunk它通过汇编编程解决了这一问题,不过对平台的兼容性不好。
为了完成自己的想法,我结合自己所学的一些C++知识完成了解决这一问题的办法。
构建回调测试
为了方便快捷,我们肯定不能直接使用libuv里面的函数进行回调测试,因此我自己写了一点代码,模拟了回调过程。
extern "C" {
typedef struct {
int value;
void *data;
}req_t;
typedef void (*call_t)(req_t *a, int b, double c);
int call_back_function(req_t *data, call_t func) {
data->value = 1023;
func(data, 1, 2.0);
return 0;
}
}
需要调用的回调函数及类
class A {
public:
int s = 10;
void true_call_back(req_t *t, int b, double c) {
std::cout << t->value << std::endl;
std::cout << s << std::endl;
}
};
整个过程就是call_back_function调用A::true_call_back完成回调过程。
解决方法
template<typename T, typename S>
struct data_t{
T& t;
S call_it;
};
template<typename S, typename T, typename ... Args>
void common_call_back(S* req, Args... data) {
//std::cout << main_class->s << std::endl;
T* pdata = static_cast<T*>(req->data);
(pdata->t.*(pdata->call_it))(req, data...);
}
使用
int main() {
A a;
data_t<A, decltype(&A::true_call_back)> data{a, &A::true_call_back};
req_t req;
req.data = (void *)&data;
call_back_function(&req, common_call_back<req_t, decltype(data), int, double>);
}
简单来说,就是通过模板,为每一个回调产生一个函数。为了保持成员函数能够找到对应的类,使用了一个额外的结构体data_t。
引用
[1] https://github.com/libuv/libuv
[2] https://github.com/ink19/ProgramRunTest
[3] https://zhuanlan.zhihu.com/p/23952898
在C++中使用libuv时对回调的处理的更多相关文章
- 在C++中使用libuv时对回调的处理 (2)
前情简介 在完成了第一版的<在C++中使用libuv时对回调的处理>之后,在对项目进行开发的时候,还是感觉有一些难受. 因为在实际操作的时候,需要构建一个结构体,并且需要对这个结构体的内存 ...
- 采用指数退避算法实现ajax请求的重发,全部完成时触发回调函数
目录: 0.Chrome扩展开发(Gmail附件管理助手)系列之〇——概述 1.Chrome扩展开发之一——Chrome扩展的文件结构 2.Chrome扩展开发之二——Chrome扩展中脚本的运行机制 ...
- jQuery中ajax方法无法执行回调函数问题
最近遇到一个问题,发现使用jquery的ajax方法时,回调方法无法执行,而使用$.load()方法时却能正确返回数据.经过长时间调试最终发现是自己粗心大意,原来后台返回的是json数据,而返回的数据 ...
- 在Amazon FreeRTOS V10中使用运行时统计信息
在MCU on Eclipse网站上看到Erich Styger在8月2日发的博文,一篇关于在Amazon FreeRTOS V10中使用运行时统计信息的文章,本人觉得很有启发,特将其翻译过来以备参考 ...
- Object—C 块在函数中作为参数时的分析
暂时对这个有了一些粗浅的理解,记下来一边后面学习时学习,改正. 先举个例子: A类: .h文件: @interface A : NSObject - (void)Paly1:(void (^)(do ...
- js的for循环中出现异步函数,回调引用的循环值总是最后一步的值?
这几天跟着视频学习node.js,碰到很多的异步函数的问题,现在将for循环中出现的异步函数回调值的问题总结如下: 具体问题是关于遍历文件夹中的子文件夹的,for循环包裹异步函数的代码: for (v ...
- 在php中定义常量时,const与define的区别?
问]在php中定义常量时,const与define的区别? [答]使用const使得代码简单易读,const本身就是一个语言结构,而define是一个函数.另外const在编译时要比define快很 ...
- AndRodi Strudio中的按钮时件
AndRodi Studio中的按钮时件注册一定要写在onCraete中 @Override protected void onCreate(Bundle savedInstanceState) { ...
- 在MySQL向表中插入中文时,出现:incorrect string value 错误
在MySQL向表中插入中文时,出现:incorrect string value 错误,是由于字符集不支持中文.解决办法是将字符集改为GBK,或UTF-8. 一.修改数据库的默认字符集 ...
随机推荐
- go语言字符串的处理与json转换
1 字符串的处理 可以通过Go标准库中的strings和strconv两个包中的函数进行相应的操作 1 字符串的操作 func Contains(s, substr string) bool 字符串s ...
- VUE响应式原理-如何追踪变化
Vue 最独特的特性之一,是其非侵入性的响应式系统.数据模型仅仅是普通的 JavaScript 对象.而当你修改它们时,视图会进行更新.这使得状态管理非常简单直接 如何追踪变化 当你把一个普通的 Ja ...
- Cookie:SameSite,防止CSRF攻击
前言 最近在本地调试时,发现请求接口提示“未登录”,通过分析HTTP请求报文发现未携带登录状态的Cookie: PS:登录状态Cookie名是TEST 再进一步分析,发现Cookie的属性SameSi ...
- Spine学习九 - 冰冻效果
想象这样一个效果,一个人被冰霜攻击命中,然后这个人整个就被冰冻了,那么spine动画要如何实现这个效果呢? 1.首先需要一个Spine动画,这个动画应该是相对静止的,因为人物已经被冰冻了,那么这个人儿 ...
- BootStrap-select插件动态添加option无法显示
问题描述: 在使用bootstrap-select插件时出现下拉框无法显示动态追加的option,经过查看element元素发现,select标签已经append进去了所需的option选项,但是页面 ...
- [Oracle/sql]查看当前用户名下有多少表 以及查看表字段信息
SQL> select table_name from user_tables order by table_name; TABLE_NAME ------------------------- ...
- Tomcat源码分析(从启动流程到请求处理)
Tomcat 8.5下载地址 https://tomcat.apache.org/download-80.cgi Tomcat启动流程 Tomcat源码目录 catalina目录 catalina包含 ...
- html基础:jquery的ajax获取form表单数据
jq是对dom进行的再次封装.是一个js库,极大简化了js使用 jquery库在js文件中,包含了所有jquery函数,引用:<script src="jquery-1.11.1.mi ...
- Python中的枚举enumerate
- defer implement for C/C++ using GCC/Clang extension
前述: go 中defer 给出了一种,延时调用的方式来释放资源.但是对于C/C++去没有内置的这种属性.对于经常手动管理内存的C/C++有其是C程序员这种特性显得无比重要.这里给出了一种基于GCC/ ...