在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. 一.修改数据库的默认字符集 ...
随机推荐
- [PyTorch 学习笔记] 3.3 池化层、线性层和激活函数层
本章代码:https://github.com/zhangxiann/PyTorch_Practice/blob/master/lesson3/nn_layers_others.py 这篇文章主要介绍 ...
- Azure Storage 系列(一)入门简介
一,引言 今天作为新的Azure 资源介绍的开篇,我们来学习一个新的服务,Azure Storage.众所周知,我们实际在开发过程中,会需要存储一些比如说日志,图片,等等,各种类型的数据.比如说存储图 ...
- Update LateUpdae FixedUpdate
这个问题本来是在研究动画系统时遇到的:OnAnimatorMove在Animator.Update()调用,那这个Animator.Update是什么时候调用的呢. Animator Componen ...
- wpf之DataGrid绑定DataTable,其中DataGridComboBoxColumn双向绑定枚举enum
百度了快一天,没结果,除了几个原创的,都是复制粘贴的内容. 不想用别的笨办法,于是脑洞大开,想出了我的办法. 首先是前台代码,与网上的比较类似: xmlns:jz="clr-namespac ...
- 三层架构的一点理解以及Dapper一对多查询
1.首先说一下自己对三层架构的一点理解 论坛里经常说会出现喜欢面相对象的写法,所以使用EF的,我个人觉得他俩没啥关系,先别反对,先听听我怎么说吧. 三层架构,基本都快说烂了,但今天还是说三层架构:UI ...
- Python实践项目2
#南昌理工学院人工智能学院实验室WORKSHOP实践项目 import time import random SCRIPT_NPC_SCHOOL_SISTER = ['你好!', '你好!', '你是 ...
- C# 读取 ttf字体文件里的 Unicode
因为爬虫要解析 򈃌这种字体编码的值,下载到一个ttf文件,用百度字体编辑器 打开,可以看到每个字符对应的Unicode (数字下方 $23.$2A...这些), 我需要拿到这些映 ...
- memcached缓存:安装和清缓存
一.安装步骤: 1.将工具一直解压,解压到最底层的exe目录
- [程序员代码面试指南]二叉树问题-找到二叉树中的最大搜索二叉树(树形dp)
题意 给定一颗二叉树的头节点,已知所有节点的值都不一样,找到含有节点最多的搜索二叉子树,并返回这个树的头节点. 题解 在后序遍历过程中实现. 求解步骤按树形dp中所列步骤.可能性三种:左子树最大.右子 ...
- 安装Linux的CentOS操作系统 - 初学者系列 - 学习者系列文章
Linux系统对于一些熟悉Windows操作系统的用户来说可能比较陌生,但是它也是一种多用户.多任务的操作系统,现在也发展成为了多种版本的操作系统了.如果想对该系统进行学习,请下载这个学习文档:htt ...