当前位置: 首页 > news >正文

C++11——function与bind

包装器

  • function包装器
    • function的介绍
    • function的使用
    • function的使用场景
    • function的意义
  • bind包装器
    • bind的介绍
    • bind的使用

function包装器

function的介绍

function是用来包装函数的,所以叫做包装器或者适配器,fuction的本质其实是一个类模板
function的类模板如下:

template <class T> function;     // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;

参数说明:

  • Ret:被包装的可调用对象的返回值类型。
  • Args…:被包装的可调用对象的形参类型。

function的使用

在使用function的时候,需要包含头文件#include< functional >
function可以对一下五种函数进行包装:

  • 函数指针
int add(int a, int b)
{return a + b;
}
int main()
{std::function<int(int, int)> func1 = add;//传递函数指针std::cout << func1(1, 1) << std::endl;return 0;
}
  • 仿函数(函数对象)
struct plus
{int operator()(int a,int b){return a + b;}
};
int main()
{std::function<int(int, int)> func2 = plus();//传递仿函数(函数对象)std::cout << func2(3, 4) << std::endl;return 0;
}

需要注意的是,传递的是一个函数对象,因为仿函数operator()是创建在对象中的

  • lambda表达式
int main()
{std::function<int(int, int)> func3 = [](int a, int b)->int {return a + b; };//传递lambda函数std::cout << func3(5, 6) << std::endl;return 0;
}
  • 静态成员函数
class Func
{
public:static int addi(int a,int b){return a + b;}double addd(double a,double b){return a  + b;}
};
int main()
{std::function<int(int, int)> func4 = &Func::addi;//传递静态类成员函数,可以省略&std::cout << func4(5, 6) << std::endl;return 0;
}
  • 传递非静态成员函数
class Func
{
public:static int addi(int a,int b){return a + b;}double addd(double a,double b){return a  + b;}
};
int main()
{std::function<int(Func,double, double)> func5 = &Func::addd;//传递非静态成员函数,不可以省略&std::cout << func5(Func(), 5.5, 6.6) << std::endl;return 0;
}

需要注意的,在传递非静态成员函数的时候,&是不可以省略的,而且还要多传递一个成员变量this指针,所以可以就传递一个临时变量Func()。

function的使用场景

统一类型的使用场景:
函数模板会根据不同的模板参数,实例化出等同于不同模板参数函数的实例,假设有一个函数模板:
第一个模板参数是可以任意调用的函数指针,仿函数,lambda表达式;
第二个模板参数是任意的自定义类型或内置类型。

template<class T,class F>
T useF(F f,T a)
{static int num = 0;cout << "num的值: " << ++num << endl;cout << "num的地址: " << &num << endl;return f(a);
}
int add(int a)
{return 1 + a;
}
struct Func 
{int operator()(int a){return 1 + a;}
};
int main()
{cout << useF(add,1) << endl;cout << useF(Func(),1) << endl;cout << useF([](int a)->int {return 1 + a; }, 1) << endl;return 0;
}

在这里插入图片描述
这样实例化出来了三份不同的函数实例,造成这样的现象是因为第一个模板参数。
现在有解决方法就是吧,函数指针和仿函数以及lambda全部都用function包装起来,然后再传给useF那么就只会实例化出来一份函数实例。
在这里插入图片描述

function的意义

  • 将可调用对象的类型进行统一,便于对其进行统一化管理。
  • 包装后明确了可调用对象的返回值和形参类型,更加方便使用者使用。

bind包装器

bind的介绍

bind也是可以包装函数的一种方法,bind可以包装一个可调用的对象(函数),然后生成一个新的可调用对象(函数)去适配原来这个可调用对象(函数)的参数bind的本质是一个函数模板

template <class Fn, class... Args>
/* unspecified */ bind(Fn&& fn, Args&&... args);
template <class Ret, class Fn, class... Args>
/* unspecified */ bind(Fn&& fn, Args&&... args);

参数说明:

  • Fn:可调用的对象
  • Args:参数列表,占位符

bind的使用

调用bind的一般形式为:auto newCallable = bind(callable, arg_list);

  • callable:需要包装的可调用对象。
  • newCallable:生成的新的可调用对象。
  • arg_list:逗号分隔的参数列表,对应给定的callable的参数。当调用newCallable时,newCallable会调用callable,并传给它arg_list中的参数。
int sub(int a, int b)
{return a - b;
}
int main()
{auto newsub = bind(sub,placeholders::_1,placeholders::_2);cout << newsub(2,1) << endl;
}

auto可以用function来代替,function<()()> newCallable = bind(callable, arg_list);

int sub(int a, int b)
{return a - b;
}
int main()
{function<int(int, int)> newsub = bind(sub, placeholders::_1, placeholders::_2);cout << newsub(2, 1) << endl;
}

其中的placeholsers::_1和placeholders::_2,对应的就是sub的第一个参数和第二个参数。
bind传递参数的顺序
在这里插入图片描述
placeholders_n,是按照顺序绑定可调用对象的参数的是不会改变的。
bind包装类成员函数:

class func
{
public:int sub(int a, int b){return a - b;}
};
int main()
{function<int(int, int)> newsub = bind(&func::sub,func(),placeholders::_1,placeholders::_2);cout << newsub(2,1)  << endl;return 0;
}

需要注意:类成员函数的又this指针,所以需要在传递可调用对象这个参数之后,再传递一个临时变量给this指针。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Vue3 : Pinia的性质与作用
  • react jsx
  • Java基础(中)
  • 进阶版水仙花数水是指一个n位数,各个位数字的n次方之和等于该数字本身
  • 《华为三台交换机堆叠的详细命令行配置示例》
  • flink自定义process,使用状态求历史总和(scala)
  • OpenSSH从7.4升级到9.8的过程 亲测--图文详解
  • 安卓13设置动态显示隐藏第一页的某一项 动态显示隐藏无障碍 android13设置动态显示隐藏第一页的某一项
  • 4款音频转文字在线转换工具帮你解锁新的记录模式。
  • RabbitMQ 高级特性——发送方确认
  • 力扣239 滑动窗口最大值 Java版本
  • C++ 新特性
  • Ceph官方文档_02_Ceph初学者指南
  • 基于php的小说阅读系统
  • docker安装及使用
  • conda常用的命令
  • ES学习笔记(12)--Symbol
  • Kibana配置logstash,报表一体化
  • Laravel 实践之路: 数据库迁移与数据填充
  • MD5加密原理解析及OC版原理实现
  • Node 版本管理
  • Sass Day-01
  • Theano - 导数
  • underscore源码剖析之整体架构
  • VUE es6技巧写法(持续更新中~~~)
  • 服务器从安装到部署全过程(二)
  • 记录一下第一次使用npm
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 实战|智能家居行业移动应用性能分析
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • 携程小程序初体验
  • 学习使用ExpressJS 4.0中的新Router
  • 一些关于Rust在2019年的思考
  • 优秀架构师必须掌握的架构思维
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • ​业务双活的数据切换思路设计(下)
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • # Redis 入门到精通(一)数据类型(4)
  • $.proxy和$.extend
  • (¥1011)-(一千零一拾一元整)输出
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (JSP)EL——优化登录界面,获取对象,获取数据
  • (LeetCode) T14. Longest Common Prefix
  • (MTK)java文件添加简单接口并配置相应的SELinux avc 权限笔记2
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (二)学习JVM —— 垃圾回收机制
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (利用IDEA+Maven)定制属于自己的jar包
  • (六)软件测试分工
  • (全注解开发)学习Spring-MVC的第三天
  • (转)负载均衡,回话保持,cookie
  • **《Linux/Unix系统编程手册》读书笔记24章**
  • .gitignore不生效的解决方案
  • .md即markdown文件的基本常用编写语法
  • .NET Core 中插件式开发实现