前情简介

在完成了第一版的《在C++中使用libuv时对回调的处理》之后,在对项目进行开发的时候,还是感觉有一些难受。

因为在实际操作的时候,需要构建一个结构体,并且需要对这个结构体的内存进行管理,非常的麻烦。

在对C++的模板编程进行简单的学习后,了解到一个比较基本的知识。如果一个值或者类型能在编译的时候确定,那么它是一定可以作为模板参数的。

反观我之前为了完成操作构建的结构体,可以很明显的发现,成员函数指针那一个变量是一直保持不变的,而且可以在编译的时候确定,所以是有办法将成员函数指针放入模板里面的。

解决方案

使用回调的函数

typedef struct {
void *data;
int s;
} call_back_t; typedef void (*call_back_func_t)(call_back_t *t, int s, int v); int call_back_func(call_back_t *t, call_back_func_t func) {
func(t, t->s, 12);
return 0;
}

回调函数及其类

class CallBack {
public:
int a = 0;
void call_back(call_back_t *t, int s, int v) {
std::cout << "t->s:" << t->s << std::endl;
std::cout << "s:" << s << std::endl;
std::cout << "v:" << v << std::endl;
std::cout << "a:" << a << std::endl;
}
};

解决方案

template<typename T,  T>
struct comm_call_back_s; template<typename ClassType, typename ...ArgTypes, void (ClassType::*FunType)(call_back_t *t, ArgTypes...) >
struct comm_call_back_s<void (ClassType::*)(call_back_t *t, ArgTypes...), FunType> {
static void comm_call_back(call_back_t *t, ArgTypes... Value) {
ClassType *mClass = static_cast<ClassType *>(t->data);
(mClass->*FunType)(t, std::forward<ArgTypes>(Value)...);
}
}; #define define_comm_call_back_s(F) (comm_call_back_s<decltype((F)), (F)>::comm_call_back)

以上代码是根据[1]中大佬代码修改得来的。首先是第一段

template<typename T,  T>
struct comm_call_back_s;

这一段代码定义了模板的原型,模板包括两个参数。一个是类型T,另一个是类型为T的值。

template<typename ClassType, typename ...ArgTypes, void (ClassType::*FunType)(call_back_t *t, ArgTypes...) >
struct comm_call_back_s<void (ClassType::*)(call_back_t *t, ArgTypes...), FunType> {
static void comm_call_back(call_back_t *t, ArgTypes... Value) {
ClassType *mClass = static_cast<ClassType *>(t->data);
(mClass->*FunType)(t, std::forward<ArgTypes>(Value)...);
}
};

第二段代码是我们主要使用的偏特化模板。一共定义了三个模板参数,第一个是包含回调函数的类,第二个是回调函数的部分参数,第三个是回调函数。

在具体的特化中,我们将回调函数的类型作为原型里面的类型T,回调函数作为值。

然后,我们定义了一个comm_call_back函数作为我们封装的回调函数。

#define define_comm_call_back_s(F) (comm_call_back_s<decltype((F)), (F)>::comm_call_back)

最后一段,我们定义了一个宏,方便我们的调用。

使用

int main() {
CallBack b;
b.a = 100;
call_back_t call;
call.s = 1024;
call.data = static_cast<void *>(&b);
call_back_func(&call, define_comm_call_back_s(&CallBack::call_back));
}

完整代码示范

反思

在写完这一些代码后,我思考了几个问题,并做了一定的解答。

  1. 为什么使用结构体,而不直接使用模板函数。

    因为我们在定义模板原型的时候没办法决定函数的参数,所以先使用结构体定义,然后使用偏特化实现具体的函数。

引用

[1] https://stackoverflow.com/questions/9779105/generic-member-function-pointer-as-a-template-parameter

在C++中使用libuv时对回调的处理 (2)的更多相关文章

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

    新的解决方法 https://www.cnblogs.com/ink19/p/13768425.html libuv简介 libuv是一个可以跨平台的C语言库,它提供了基于事件的异步IO支持[1].提 ...

  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. 04.简单了解一下Redis企业级数据备份方案

    一.企业级的持久化的配置策略 (1)每隔1分钟去检查如果超过10000个可以变更,则生成一个快照.RDB最多丢1分钟的数据. save 60 10000 (2)AOF一定要打开,fsync,every ...

  2. Java Android程序员软件开发知识:枚举的介绍,以及代码的编写教程。

    Java枚举 Java 5.0引入了枚举,枚举限制变量只能是预先设定好的值.使用枚举可以减少代码中的bug. 例如,我们为果汁店设计一个程序,它将限制果汁为小杯.中杯.大杯.这就意味着它不允许顾客点除 ...

  3. 虚拟机安装:VirtualBox上安装Ubuntu

    在Win10 中使用VirtualBox安装Ubuntu 本教程将指引读者在Windows10操作系统下使用开源虚拟机软件VirtualBox安装Ubuntu,读者也可以使用其他虚拟机VMware W ...

  4. 关于pom.xml文件中配置jquery,以及如何在jsp中引入

    pom.xml <!-- 对jquery的支持 --> <dependency> <groupId>org.webjars.bower</groupId> ...

  5. JVM中的对象

    虚拟机中的对象 对象的分配 虚拟机遇到一条new指令时:根据new的参数是否能在常量池中定位到一个类的符号引用,如果没有,说明还未定义该类,抛出ClassNotFoundException: 1)检查 ...

  6. leetcode刷题-57插入区间

    题目 给出一个无重叠的 ,按照区间起始端点排序的区间列表. 在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间). 示例 1: 输入:intervals = ...

  7. 【小白学PyTorch】9 tensor数据结构与存储结构

    文章来自微信公众号[机器学习炼丹术]. 上一节课,讲解了MNIST图像分类的一个小实战,现在我们继续深入学习一下pytorch的一些有的没的的小知识来作为只是储备. 参考目录: @ 目录 1 pyto ...

  8. git仓库个人和企业版新增仓库和成员

    1.首先要在本地安装一个git安装包,比如安装完之后路径是在      D:\Program Files (x86)\Git\bin\git.exe 2.访问git网址  https://gitee. ...

  9. Web_php_unserialize 攻防世界

    1.$var输入处有一个正则过滤 2._wakeup处需要过滤 编写脚本如下 后在网页输入?var=TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4Oi ...

  10. 安装最新LAMP环境(CentOS7+PHP7.1.5+Mysql5.7)

    安装Apache&Nginx ①.升级一下yum源(不是必须的),升级会花点时间,需要选择的地方都选择都输入“y”即可 yum update ②. 安装Apache yum list |gre ...