在C++中使用libuv时对回调的处理 (2)
前情简介
在完成了第一版的《在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] https://stackoverflow.com/questions/9779105/generic-member-function-pointer-as-a-template-parameter
在C++中使用libuv时对回调的处理 (2)的更多相关文章
- 在C++中使用libuv时对回调的处理
新的解决方法 https://www.cnblogs.com/ink19/p/13768425.html libuv简介 libuv是一个可以跨平台的C语言库,它提供了基于事件的异步IO支持[1].提 ...
- 采用指数退避算法实现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. 一.修改数据库的默认字符集 ...
随机推荐
- 2020,6招玩转 Appium 自动化测试
Appium是个什么鬼 Appium是一个移动端的自动化框架,可用于测试原生应用,移动网页应用和混合型应用,且是跨平台的.可用于IOS和Android以及firefox的操作系统.原生的应用是指用an ...
- Angular 之我见
很久没有写过技术软文了,虽然 Angular 发布已有四年,得到了越来越多人的关注,但是仍然有很多人不分青红皂白的进行诋毁.我打算结合自己的经历从客观的角度说聊一聊我眼中的 Angular. 本人刚做 ...
- .Net Task 异步执行不等待结果返回
该文章适合有一定异步编程基础的童鞋 开始之前先看.NET官网的一张图: 异步编程中最需弄清的是控制流是如何从方法移动到方法的. 没有理解的话可以去看一下 https://docs.microsoft. ...
- 教你如何在linux操作系统下玩【俄罗斯方块】高清+语音教程
主讲人小冰QQ:986945193 新浪微博:http://weibo.com/mcxiaobing 百度贴吧:忆驹家族小冰 腾讯微博:http://t.qq.com/q986945193 高清视频 ...
- 绝世好题(线性dp)
给定一个长度为n的数列ai,求ai的子序列bi的最长长度,满足bi&bi-1!=0(2<=i<=len). Input 输入文件共2行. 第一行包括一个整数n. 第二行包括n个 ...
- linux的五种IO模型
概念: 同步.异步.阻塞.非阻塞的概念 同步:所谓同步,发起一个功能调用的时候,在没有得到结果之前,该调用不返回,也就是必须一件事一件事的做,等前一件做完了,才能做下一件. 提交请求->等待服务 ...
- 使用Telnet服务测试端口时,提示没有Telnet服务
1.win7系统是默认不开启Telnet服务的,所以我们第一次使用时要手动开启Telnet服务 1)打开 控制面板 > 程序 > 程序功能 > 打开或关闭Windows功能,勾选上T ...
- 如何让SpringBoot工程在log/控制台中实时打印MyBatis执行的SQL语句
工程下载:https://files.cnblogs.com/files/xiandedanteng/gatling20200429-4.zip 其实就是一句话设置的事情,实现步骤: 在applica ...
- Mysql数据库扩展
安装跟卸载 Mysql安装 下载Mysql源安装包 1 wget http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.r ...
- Java原生网络编程
一些常见术语 编程中的Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面 ...