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

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

前言:

        上文我们学了C++11中一个新的表达式:Lambda表达式。Lambda表达式可以在函数内部定义,其本质是仿函数【C++11】Lambda表达式-CSDN博客

        本文我们来学习C++11的下一个新语法:包装器

function

function的定义为:

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

         function的一个类模板,也是一个包装器。function的实例对象可以包装调用一切可调用对象。但若function的对象为被初始化,进行调用就会报错(抛异常:std::bad_function_call)

        function模板类放在<functional>头文件中

        使用function包装不同的可调用对象,就可以用相同的方式调用不同可调用对象

        function的本质其实也是仿函数

  使用细节如下:

#include<iostream>
#include<functional>
using namespace std;
//function可以包装一切可调用对象,其本质是仿函数//template <class Ret, class... Args>
//class function<Ret(Args...)>;int f(int a, int b)
{return a + b;
}struct Functor
{int operator() (int a, int b){return a - b;}
};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)> a = f;function<int(int, int)> b = Functor();function<int(int, int)> c = [](int a, int b) {return a * 10 + b; };cout << a(1, 2) << endl;cout << b(1, 2) << endl;cout << c(1, 2) << endl;//既然说function可以包装一切可调用对象,那么类成员函数既然也可以被包装//包装静态成员函数: 1.必须要指定类域,2.非静态成员必须要取地址,但是静态不用,为了同一格式建议加上function<int(int, int)> x = &Plus::plusi;cout << x(1, 2) << endl;//包装非静态成员函数:1.必须要指定类域 2.必须取地址 3.非静态成员函数有this指针function<int(Plus*,int, int)> y = &Plus::plusd;Plus p;cout << y(&p, 1, 2) << endl;//也可以直接传对象,因为:类成员函数的调用是通过 .* 运算符实现的//前面传指针,也是先将指针解引用为对象,再通过 .* 运算符调用成员函数function<int(Plus, int, int)> z = &Plus::plusd;cout << z(p, 1, 2) << endl;//与直接传对象类似,引用是为了减少拷贝,提高效率function<int(Plus&&, int, int)> q = &Plus::plusd;cout << q(move(p), 1, 2) << endl;function<int(Plus&, int, int)> w = &Plus::plusd;cout << w(p, 1, 2) << endl;
}

        包装其他可调用对象,没什么区别,唯独需要注意当我们在包装类成员函数时有一些不同:

        包装静态成员函数时:1.必须要指定类域,2.非静态成员必须要取地址,但是静态不用,为了统一格式建议加上。

        包装非静态成员函数时:1.必须要指定类域 2.必须取地址 3.非静态成员函数有this指针。

练习:150. 逆波兰表达式求值 - 力扣(LeetCode)

#include<iostream>
#include<vector>
#include<functional>
#include<map>
#include<stack>
#include<string>
using namespace std;class Solution
{
public:int evalRPN(vector<string>& tokens){stack<int> s;//使用map将运算符与运算逻辑匹配//使用Lambda实现运算逻辑//利用function包装Lambdamap<string, function<int(int, int)>> m ={{"+",[](int a,int b) {return a + b; }},{"-",[](int a,int b) {return a - b; }},{"*",[](int a,int b) {return a * b; }},{"/",[](int a,int b) {return a / b; }}};for (auto& e : tokens){//当count返回不是0,说明当前的字符是"+ - * /"中的一个//取两个操作数,进行相应的运算if (m.count(e)){int left = s.top();s.pop();int right = s.top();s.pop();//operator[]返回function对象的引用//function对象直接调用Lambda表达式int num = m[e](right, left);s.push(num);}else{s.push(stoi(e));//stoi函数:将字符串转化为整型}}return s.top();}
};int main()
{vector<string> arr = { "4","13","5","/","+" };cout << Solution().evalRPN(arr);
}

bind

bind的定义:

simple(1)
template <class Fn, class... Args>/* unspecified */ bind (Fn&& fn, Args&&... args);with return type (2)
template <class Ret, class Fn, class... Args>/* unspecified */ bind (Fn&& fn, Args&&... args);

        bind的一个模板函数,也是一个包装器,可以将其看作一个函数适配器。bind接收一个函数处理后会返回一个可调用对象。bind的功能:调整函数参数顺序、控制函数参数个数

        调用bind的一般形式为:auto newCallable = bind(callable,arg_list);callable是函数地址,newCallable是可调用对象,调用newCallable会将arg_list的参数传给callable,然后调用callable。bind的底层和function一样都是仿函数,所以也可以用function代替auto来接收bind的返回对象

        在arg_list中有一个特殊概念:占位符。假设有n个参数,那占位符至多有n个:_1 , _2 , _3 , ....... , _n。_1代表第一个参数,_2代表第二个参数,........ ,_n代表第n个参数。这些占位符放在placeholders命名空间

使用样例:

#include<iostream>
#include<functional>
using namespace std;
//bind的占位符都放在这个命名空间里
using namespace placeholders;//bind有两个作用:1.交换参数顺序 2.绑定参数,控制参数个数(常用)
//bind的本质和function一样都是仿函数class Plus
{
public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;}
};int add(int a, int b)
{return a - b;
}int add1(int a, int b, int c)
{return a * 10 + b - c;
}int main()
{//调整参数顺序(没什么用处)auto e = bind(add, _1, _2);cout<<e(2, 3)<<endl;auto x = bind(add, _2, _1);cout << x(2, 3) << endl;//调整参数个数(常用)//直接绑定第1、2、3的参数,传参的时候只用传未绑定的参数auto c = bind(add1, 10, _1, _2);cout << c(1,2) << endl;auto d = bind(add1, _1, 10, _2);cout << d(1, 2) << endl;auto w = bind(add1, _1, _2, 10);cout << w(1, 2) << endl;//bind常用于绑定固定参数//function<double(Plus*,double, double)> f = &Plus::plusd;function<double(double, double)> f = bind(&Plus::plusd, Plus(), _1, _2);cout<<f(1, 2)<<endl;}

        总的来看,bind有用的功能主要是控制函数参数个数常用于绑定一些固定的参数

相关文章:

  • 【BotSharp框架示例 ——实现聊天机器人,并通过 DeepSeek V3实现 function calling】
  • 【MuJoCo仿真】开源SO100机械臂导入到仿真环境
  • 在 Ubuntu 上离线安装 ClickHouse
  • ShaderToy学习笔记 05.3D旋转
  • 人工智能数学基础(三):微积分初步
  • 深入解析常见排序算法及其 C# 实现
  • 初识Redis · 分布式锁
  • Go 语言中的 `recover()` 函数详解
  • 医疗生态全域智能化:从技术革新到价值重塑的深度探析
  • 基于Spring Boot 3.0、ShardingSphere、PostgreSQL或达梦数据库的分库分表
  • Go语言之路————接口、泛型
  • 在Anolis OS 8上部署Elasticsearch 7.16.1与JDK 11的完整指南
  • 首页数据展示
  • keep-alive具体使用方法
  • C++多线程与锁机制
  • MySQL 在 CentOS 7 环境下的安装教程
  • 如何解决 Xcode 签名证书和 Provisioning Profile 过期问题
  • 【Linux网络】深入解析I/O多路转接 - Select
  • 基于STM32的DS18B20简易温控系统LCD1602显示仿真设计
  • 论文阅读:2024 arxiv FlipAttack: Jailbreak LLMs via Flipping
  • 民生访谈|规范放生活动、提升供水品质……上海将有这些举措
  • 淮安四韵·名城新章: 网络名人领略“运河之都”魅力
  • 利物浦提前四轮英超夺冠,顶级联赛冠军数追平曼联
  • 校长套取学生伙食费设小金库,重庆通报6起违反八项规定典型问题
  • 伊朗爆炸港口已恢复货物进出口工作
  • 13家券商一季报出炉:超七成业绩预喜,财通、湘财、第一创业下滑