新的解决方法

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. go语言字符串的处理与json转换

    1 字符串的处理 可以通过Go标准库中的strings和strconv两个包中的函数进行相应的操作 1 字符串的操作 func Contains(s, substr string) bool 字符串s ...

  2. VUE响应式原理-如何追踪变化

    Vue 最独特的特性之一,是其非侵入性的响应式系统.数据模型仅仅是普通的 JavaScript 对象.而当你修改它们时,视图会进行更新.这使得状态管理非常简单直接 如何追踪变化 当你把一个普通的 Ja ...

  3. Cookie:SameSite,防止CSRF攻击

    前言 最近在本地调试时,发现请求接口提示“未登录”,通过分析HTTP请求报文发现未携带登录状态的Cookie: PS:登录状态Cookie名是TEST 再进一步分析,发现Cookie的属性SameSi ...

  4. Spine学习九 - 冰冻效果

    想象这样一个效果,一个人被冰霜攻击命中,然后这个人整个就被冰冻了,那么spine动画要如何实现这个效果呢? 1.首先需要一个Spine动画,这个动画应该是相对静止的,因为人物已经被冰冻了,那么这个人儿 ...

  5. BootStrap-select插件动态添加option无法显示

    问题描述: 在使用bootstrap-select插件时出现下拉框无法显示动态追加的option,经过查看element元素发现,select标签已经append进去了所需的option选项,但是页面 ...

  6. [Oracle/sql]查看当前用户名下有多少表 以及查看表字段信息

    SQL> select table_name from user_tables order by table_name; TABLE_NAME ------------------------- ...

  7. Tomcat源码分析(从启动流程到请求处理)

    Tomcat 8.5下载地址 https://tomcat.apache.org/download-80.cgi Tomcat启动流程 Tomcat源码目录 catalina目录 catalina包含 ...

  8. html基础:jquery的ajax获取form表单数据

    jq是对dom进行的再次封装.是一个js库,极大简化了js使用 jquery库在js文件中,包含了所有jquery函数,引用:<script src="jquery-1.11.1.mi ...

  9. Python中的枚举enumerate

  10. defer implement for C/C++ using GCC/Clang extension

    前述: go 中defer 给出了一种,延时调用的方式来释放资源.但是对于C/C++去没有内置的这种属性.对于经常手动管理内存的C/C++有其是C程序员这种特性显得无比重要.这里给出了一种基于GCC/ ...