新的解决方法

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时对回调的处理的更多相关文章

  1. 在C++中使用libuv时对回调的处理 (2)

    前情简介 在完成了第一版的<在C++中使用libuv时对回调的处理>之后,在对项目进行开发的时候,还是感觉有一些难受. 因为在实际操作的时候,需要构建一个结构体,并且需要对这个结构体的内存 ...

  2. 采用指数退避算法实现ajax请求的重发,全部完成时触发回调函数

    目录: 0.Chrome扩展开发(Gmail附件管理助手)系列之〇——概述 1.Chrome扩展开发之一——Chrome扩展的文件结构 2.Chrome扩展开发之二——Chrome扩展中脚本的运行机制 ...

  3. jQuery中ajax方法无法执行回调函数问题

    最近遇到一个问题,发现使用jquery的ajax方法时,回调方法无法执行,而使用$.load()方法时却能正确返回数据.经过长时间调试最终发现是自己粗心大意,原来后台返回的是json数据,而返回的数据 ...

  4. 在Amazon FreeRTOS V10中使用运行时统计信息

    在MCU on Eclipse网站上看到Erich Styger在8月2日发的博文,一篇关于在Amazon FreeRTOS V10中使用运行时统计信息的文章,本人觉得很有启发,特将其翻译过来以备参考 ...

  5. Object—C 块在函数中作为参数时的分析

    暂时对这个有了一些粗浅的理解,记下来一边后面学习时学习,改正. 先举个例子: A类: .h文件: @interface A  : NSObject - (void)Paly1:(void (^)(do ...

  6. js的for循环中出现异步函数,回调引用的循环值总是最后一步的值?

    这几天跟着视频学习node.js,碰到很多的异步函数的问题,现在将for循环中出现的异步函数回调值的问题总结如下: 具体问题是关于遍历文件夹中的子文件夹的,for循环包裹异步函数的代码: for (v ...

  7. 在php中定义常量时,const与define的区别?

    问]在php中定义常量时,const与define的区别?  [答]使用const使得代码简单易读,const本身就是一个语言结构,而define是一个函数.另外const在编译时要比define快很 ...

  8. AndRodi Strudio中的按钮时件

    AndRodi Studio中的按钮时件注册一定要写在onCraete中 @Override protected void onCreate(Bundle savedInstanceState) { ...

  9. 在MySQL向表中插入中文时,出现:incorrect string value 错误

    在MySQL向表中插入中文时,出现:incorrect string value 错误,是由于字符集不支持中文.解决办法是将字符集改为GBK,或UTF-8.      一.修改数据库的默认字符集   ...

随机推荐

  1. [PyTorch 学习笔记] 3.3 池化层、线性层和激活函数层

    本章代码:https://github.com/zhangxiann/PyTorch_Practice/blob/master/lesson3/nn_layers_others.py 这篇文章主要介绍 ...

  2. Azure Storage 系列(一)入门简介

    一,引言 今天作为新的Azure 资源介绍的开篇,我们来学习一个新的服务,Azure Storage.众所周知,我们实际在开发过程中,会需要存储一些比如说日志,图片,等等,各种类型的数据.比如说存储图 ...

  3. Update LateUpdae FixedUpdate

    这个问题本来是在研究动画系统时遇到的:OnAnimatorMove在Animator.Update()调用,那这个Animator.Update是什么时候调用的呢. Animator Componen ...

  4. wpf之DataGrid绑定DataTable,其中DataGridComboBoxColumn双向绑定枚举enum

    百度了快一天,没结果,除了几个原创的,都是复制粘贴的内容. 不想用别的笨办法,于是脑洞大开,想出了我的办法. 首先是前台代码,与网上的比较类似: xmlns:jz="clr-namespac ...

  5. 三层架构的一点理解以及Dapper一对多查询

    1.首先说一下自己对三层架构的一点理解 论坛里经常说会出现喜欢面相对象的写法,所以使用EF的,我个人觉得他俩没啥关系,先别反对,先听听我怎么说吧. 三层架构,基本都快说烂了,但今天还是说三层架构:UI ...

  6. Python实践项目2

    #南昌理工学院人工智能学院实验室WORKSHOP实践项目 import time import random SCRIPT_NPC_SCHOOL_SISTER = ['你好!', '你好!', '你是 ...

  7. C# 读取 ttf字体文件里的 Unicode

    因为爬虫要解析 &#x880cc这种字体编码的值,下载到一个ttf文件,用百度字体编辑器 打开,可以看到每个字符对应的Unicode (数字下方 $23.$2A...这些), 我需要拿到这些映 ...

  8. memcached缓存:安装和清缓存

    一.安装步骤: 1.将工具一直解压,解压到最底层的exe目录

  9. [程序员代码面试指南]二叉树问题-找到二叉树中的最大搜索二叉树(树形dp)

    题意 给定一颗二叉树的头节点,已知所有节点的值都不一样,找到含有节点最多的搜索二叉子树,并返回这个树的头节点. 题解 在后序遍历过程中实现. 求解步骤按树形dp中所列步骤.可能性三种:左子树最大.右子 ...

  10. 安装Linux的CentOS操作系统 - 初学者系列 - 学习者系列文章

    Linux系统对于一些熟悉Windows操作系统的用户来说可能比较陌生,但是它也是一种多用户.多任务的操作系统,现在也发展成为了多种版本的操作系统了.如果想对该系统进行学习,请下载这个学习文档:htt ...