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

【C++】C++11的包装器:function与bind简介

在这里插入图片描述
各位大佬好,我是落羽!一个坚持不断学习进步的学生。
如果您觉得我的文章还不错,欢迎多多互三分享交流,一起学习进步!

也欢迎关注我的blog主页: 落羽的落羽

文章目录

  • 一、function
    • 1. 概念
    • 2. 用法
  • 二、bind
    • 1. 概念
    • 2. 用法

一、function

1. 概念

上一篇文章我们学习了lambda表达式的用法。

std::function是 C++11 标准库在 <functional> 头文件中引入的一个通用、多态的函数包装器。它的本质是一个类模板,可以包装、存储、复制和调用任何可调用对象(函数指针、仿函数、lambda表达式、bind表达式等),存储的可调用对象被称为function的目标。function不含目标则为空,调用空function的目标会抛异常。
函数指针、仿函数、lambda表达式等可调用对象的类型各不相同,function可以统一类型,对他们进行包装,这样在很多地方就方便声明可调用对象的类型。

2. 用法

在这里插入图片描述
以上是function的原型,使用语法为:

#include <functional>
std::function<返回类型(参数类型1, 参数类型2, ...)> 包装器名称;

来看一段代码实例:

#include <iostream>
#include <functional>
using namespace std;// 普通函数
int add(int a, int b) 
{return a + b;
}// Lambda表达式
auto multiply = [](int a, int b) { return a * b; };// 仿函数
struct Subtract 
{int operator()(int a, int b) const {return a - b;}
};int main() 
{// 声明一个function,他可以包装一个返回int,接受两个int参数的可调用对象function<int(int, int)> func;// 包装普通函数func = add;cout << "Add: " << func(10, 5) << endl; // 输出 15// 包装 Lambda 表达式func = multiply;cout << "Multiply: " << func(10, 5) << endl; // 输出 50// 包装仿函数对象Subtract sub;func = sub;cout << "Subtract: " << func(10, 5) << endl; // 输出 5// 甚至可以包装一个临时的Lambdafunc = [](int a, int b) { return a / b; };cout << "Divide: " << func(10, 5) <<std::endl; // 输出 2return 0;
}

有一个特殊的点是,类的成员函数也可以被包装,但成员函数必须要指定类域并且前面加上&才能获取地址,静态成员函数可以不加&,但是为了方便记忆,建议成员函数都加上吧。这时还有一个问题,普通成员函数还有一个隐含的this指针,在类外包装时,也一定要显式写出this指针参数类型,即当前类的指针类型:

class Plus
{
public:Plus(int n = 10):_n(n){}static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return (a + b) * _n;}private:int _n;
};int main()
{function<int(int, int)> f = &Plus::plusi;cout << f(1, 1) << endl; // 输出2function<double(Plus*, double, double)> f1 = &Plus::plusd;//调用时实例化出一个对象取地址传参即可,或者传对象也可以Plus pdcout << f1(&pd, 1.1, 1.1) << endl; // 输出22/*function<double(Plus, double, double)> f1 = &Plus::plusd;Plus pdcout << f1(pd, 1.1, 1.1) << endl; */return 0;
}

二、bind

1. 概念

std::bind是一个函数模板,也包含在<functional>中,是一个可调用对象的包装器,可以把他看做一个函数适配器,对接收的可调用对象处理后返回一个可调用对象。bind可以用来调整参数个数和参数顺序。
在这里插入图片描述

2. 用法

调用bind的一般形式为:auto newCallable = bind(callable, arg_list);其中newCallable本身是一个可调用对象,arg_list是一个用逗号分隔的参数列表,对应给定callable的参数。arg_list中的参数可能包含形如_n的占位符,n是一个正整数,它们占据了传递给newCallable的参数的位置。n表示生成的可调用对象的参数的位置:如_1为newCallable的第1个参数,_2为newCallable的第2个参数,_3为newCallable的第3个参数,以此类推,_1/_2/_3…这些占位符都在一个叫placeholders的命名空间中。

#include <functional>
using namespace placeholders;int Sub(int a, int b)
{return a - b;
}int main()
{// _1代表sub1的第一个参数,_2代表sub1的第二个参数。// bind内写成_2, _1的顺序,意味sub1的第二个参数会传给Sub的第一个参数a,sub1的第一个参数会传给Sub的第二个参数bauto sub1 = bind(Sub, _2, _1);cout << Sub(1, 2) << endl; cout << sub1(1, 2) << endl;return 0;
}

在这里插入图片描述
这是只改变参数顺序的一般用法。

bind还有最常用的改变参数个数用法,这个用法一般是为了绑死某些参数,使之为一个固定值,使用时就不需要再传参:

#include <functional>
using namespace placeholders;int Sub(int a, int b)
{return a - b;
}int main()
{// _1代表sub2的第一个参数,100代表绑死Sub的第一个参数a,a的值固定为100了// a的值固定了,传参时就不需要传给a,sub2的第一个参数就会传给Sub的第二个参数bauto sub2 = bind(Sub, 100, _1);cout << Sub(1, 2) << endl;cout << sub2(1);return 0;
}

在这里插入图片描述

再比如,刚才上面讲到function包装类成员函数时说到,使用包装后的对象时还需要传给this指针一个参数。有了bind就可以提前绑死这个参数,后续每次使用就不需要额外传了:

#include <functional>
using namespace placeholders;class Plus
{
public:Plus(int n = 10):_n(n){}double plusd(double a, double b){return (a + b) * _n;}
private:int _n;
};int main()
{function<double(double, double)> f = bind(&Plus::plusd, Plus(), _1, _2);cout << f(1, 2) << endl;return 0;
}

在这里插入图片描述

本篇完,感谢阅读。


文章转载自:

http://sxr9dPj7.mhnxs.cn
http://0tNCL9gN.mhnxs.cn
http://JQvpuA2B.mhnxs.cn
http://FB1icVBt.mhnxs.cn
http://ROUvdfX0.mhnxs.cn
http://ZY2v7NVy.mhnxs.cn
http://9ZyM8yMj.mhnxs.cn
http://skEvsZqE.mhnxs.cn
http://T8BglkEk.mhnxs.cn
http://OhhvVGBk.mhnxs.cn
http://hR7p9RPH.mhnxs.cn
http://VTMjkrFN.mhnxs.cn
http://1mXOHfO7.mhnxs.cn
http://LdH6i250.mhnxs.cn
http://IIhoWUs0.mhnxs.cn
http://GyoyeX28.mhnxs.cn
http://jUtXFpm1.mhnxs.cn
http://BYbpvCav.mhnxs.cn
http://vZkIeTPb.mhnxs.cn
http://KEWYOyGh.mhnxs.cn
http://NbiLKOds.mhnxs.cn
http://LCoM7pL6.mhnxs.cn
http://Nl9E9Mv5.mhnxs.cn
http://sYUpIXdi.mhnxs.cn
http://QEuYMLs9.mhnxs.cn
http://fhyxZEP0.mhnxs.cn
http://Iy7RYJeh.mhnxs.cn
http://AslbIsBL.mhnxs.cn
http://w8Lm9UvW.mhnxs.cn
http://UgXlCeea.mhnxs.cn
http://www.dtcms.com/a/372931.html

相关文章:

  • C++微基础备战蓝桥杯之旅
  • 解构服务于构建
  • 天津大学智算2026预推免机试第二批题目及代码c++
  • 杰理烧录ERROR: Data error after erasing, address = 0x430000
  • Spring Cloud Alibaba快速入门02-Nacos(下)
  • DA-WSOL
  • FlutterActivity vs FlutterFragmentActivity:全面对比与最佳实践
  • 算法高频题
  • Aider AI Coding 项目 LLM 模型管理 深度分析
  • Spring事件监听机制(三)
  • 设计模式之单例模式大全---java实现
  • Separated collaborative learning
  • Microsoft Visual C++ 运行库安装教程(最新版完整指南 | DLL修复方案)
  • 【Linux】vim工具篇
  • 迁移学习:人工智能的智慧传承与革新之道
  • SQL面试题及详细答案150道(116-135) --- 高级查询与函数篇
  • LRU 缓存
  • Redis的Feed流实现方案
  • 5G专网、物联网专业技术知识
  • LaTeX TeX Live 安装与 CTAN 国内镜像配置(Windows / macOS / Linux 全流程)
  • 脑电数据预处理十六:自动化阈值检测原理与实践
  • 9月8日
  • Java全栈开发工程师的实战面试经历:从基础到微服务
  • 冰火岛 Tech 传:Apple Foundation Models 心法解密(上集)
  • 腾讯云 CLB (Cloud Load Balancer) 为例,详细讲解如何配置 Nginx 集群
  • 25.线程概念和控制(二)
  • VMware-三种网络模式原理
  • 【Java实战㉝】Spring Boot实战:从入门到自动配置的进阶之路
  • 【WRF-VPRM 预处理器第一期】完整安装(服务器)
  • 【Unity笔记】Unity 编辑器扩展:打造一个可切换 Config.assets 的顶部菜单插件