C++11函数包装器

目录

std::function

注意事项

包装静态成员函数

包装非静态成员函数

std::bind

用法

应用场景


std::function

function是C++11引入的类,可以用任何可调用对象作为参数,构造出一个新对象。

可调用对象有函数指针,仿函数,lambda等

下面是function的声明

可以看到是一个类模板,第一个参数是函数返回值类型,第二个是可变参数模板,表示函数的参数列表

先看一个例子

#include<iostream>
//使用function需要包含头文件
#include<functional>
int main()
{std::function<int(int, int)> add = [](int a, int b)->int{return a + b; };std::cout << add(1, 2) << std::endl;return 0;
}

这是对lambda表达式的包装,关于lambda表达式,详见 C++11 lambda表达式-CSDN博客

function可以将一系列参数列表和返回值相同的函数用相同的类型接收,这在某些情况下提供了极大的便利。

比如对表达式求值,要根据符号是+、-、*、/中的某一个进行运算,一种选择是使用条件分支语句,也就是if或者switch case语句,但是写起来有些繁琐,这时可以使用function

#include <map>
#include <functional>
int main()
{std::map<char, std::function<int(int, int)>> op{{'+', [](int x, int y)->int {return x + y; }},{'-', [](int x, int y)->int {return x - y; }},{'*', [](int x, int y)->int {return x * y; }},{'/', [](int x, int y)->int {return x / y; }}};std::cout << op['+'](10, 20) << std::endl;return 0;
}

使用function就可以省去大量的条件判断,并且map可以随时扩展,增加新的功能。

注意事项

包装静态成员函数

class Plus
{
public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;}
};
int main()
{std::function<int(int, int)> f1 = &Plus::plusi;return 0;
}

包装非静态成员函数

第一种方法

class Plus
{
public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;}
};
int main()
{Plus p;std::function<double(Plus*, double, double)> f1 = &Plus::plusd;std::cout << f1(&p, 1.1, 2.2) << std::endl;return 0;
}

由于非静态的成员函数会有一个this指针,于是在包装时需要加上这个指针参数,在调用时要显式加上这个参数

还有一种写法

class Plus
{
public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;}
};
int main()
{std::function<double(Plus, double, double)> f1 = &Plus::plusd;std::cout << f1(Plus(), 1.1, 2.2) << std::endl;return 0;
}

这种写法与第一种的区别在于,不传入Plus*,而是传入Plus,可能你不禁会想,为什么传入Plus也可以,这里解释一种理解方式 :

function接收函数指针实例化后是一个类,这个类有operator()方法,这个方法接收了参数,在我举的例子中,参数是Plus(), 1.1, 1.2,内部不是直接显式地把这几个参数传入回调函数,而是使用类似p.plusd(1.1,1.2)或者p->plus(1.1, 1.2)进行成员函数调用。所以这里可以选择不传指针。

而且,this指针不支持显式传递,所以底层当然不是直接显式传参。

std::bind

用法

bind是一个函数模板

// 原型如下:
#include <functional>
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以某个可调用对象为参数,生成一个新的可调用对象,fn是可调用对象。

直接看下面的例子

int sub(int a, int b)
{return a - b;
}		
int main()
{auto sub1 = std::bind(sub, 1, std::placeholders::_1);std::cout << sub1(2) << std::endl;return 0;
}

sub是传入的可调用对象,1传给sub的第一个形参也就是a,std::placeholders是一个命名空间,里面有从_1,_2,...,_n很多个数字,表示第一个实参,第二个实参,...,第n个实参。

在这里表示传入的实参2

bind返回了一个可调用对象,这个可调用对象的第一个参数a被固定成了a,第二个参数是sub1传入的第一个参数,经过bind作用后,你可以理解为sub1是下面的函数

int sub1(int b)
{return 1 - b;
}

再看一个复杂点的例子

int sub(int a, int b, int c)
{return a - b - c;
}
int main()
{auto sub1 = std::bind(sub, 1, std::placeholders::_2, std::placeholders::_1);std::cout << sub1(2, 3) << std::endl;return 0;
}

a被定为了1,b是传入的第二个实参,c是传入的第一个实参

相当于

int sub1(int b, int c)
{return 1 - c - b;
}

 当然也可以

int sub(int a, int b, int c)
{return a - b - c;
}
int main()
{auto sub1 = std::bind(sub, std::placeholders::_2, 2, std::placeholders::_1);std::cout << sub1(2, 3) << std::endl;return 0;
}

这时sub1相当于

int sub1(int a, int c)
{return c - 2 - a;
}

理解了bind的用法后,来看看它的应用场景

应用场景

在使用function包装非静态成员函数时,需要多传一个参数,以上面function举的例子来看

class Plus
{
public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;}
};
int main()
{std::function<double(Plus, double, double)> f1 = &Plus::plusd;std::cout << f1(Plus(), 1.1, 2.2) << std::endl;return 0;
}

需要加一个Plus(),这时就可以使用bind

class Plus
{
public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;}
};
using namespace std::placeholders;
int main()
{std::function<double(double, double)> f1 = std::bind(&Plus::plusd, Plus(), _1, _2);std::cout << f1(1.1, 2.2) << std::endl;return 0;
}

现在使用f1就不用再传Plus()了。

而且,如果有一个函数,有绑定某个参数为某些值得需求时,bind也能派上用场

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/34671.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

maven的安装配置

目录 一、官网下载压缩包 二、配置环境变量 设置 MAVEN_HOME 添加 MAVEN_HOME\bin 到 PATH 三、配置本机仓库和远程仓库 四、配置idea 一、官网下载压缩包 Download Apache Maven – Maven 如上图。选择这个压缩包 选择好文件&#xff0c;下载完后&#xff0c;配置环境变…

分布式事务

1 事务 众所周知&#xff0c;事务具有ACID四大特性&#xff1a; 原子性&#xff08;Atomicity&#xff09;&#xff1a;事务作为一个整体被执行&#xff0c;包含在其中的对数据库的操作要么全部被执行&#xff0c;要么都不执行。 一致性&#xff08;Consistency&#xff09;&a…

Postman中Authorization和Headers的区别

案例 笔者在进行token验证的时候碰到的问题 一般如果是进行token验证&#xff0c;大部分是在Headers下面添加token名称及token的值 这样&#xff1a;后端提取请求头的token即可 还有一种是&#xff0c;左侧选择Bearer Token&#xff0c;右侧添加token的值,后端传递的 大概…

1.备战SISAP 2025挑战:调研2024挑战

简介 紧张刺激的SISAP 2025 challenge发布了&#xff0c;此博客用于记录备战的一些准备&#xff0c;思路和实验。 25年挑战介绍 详细信息参考SISAP Indexing challenge 2025 Task 1&#xff1a;内存受限索引 这项任务要求参与者开发具有reranking&#xff08;重排&#xf…

FPGA学习(二)——实现LED流水灯

FPGA学习(二)——实现LED流水灯 目录 FPGA学习(二)——实现LED流水灯一、DE2-115时钟源二、控制6个LED灯实现流水灯1、核心逻辑2、代码实现3、引脚配置4、实现效果 三、模块化代码1、分频模块2、复位暂停模块3、顶层模块 四、总结 一、DE2-115时钟源 DE2-115板子包含一个50MHz…

进程间通信--匿名管道

进程间通信介绍 进程间通信目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程资源共享&#xff1a;多个进程之间共享同样的资源。通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#xff0c;通知它&#xff08;它们&#xff09;发生了某种事件&…

【鸿蒙开发】Hi3861学习笔记-Visual Studio Code安装(New)

00. 目录 文章目录 00. 目录01. Visual Studio Code概述02. Visual Studio Code下载03. Visual Studio Code安装04. Visual Studio Code插件05. 附录 01. Visual Studio Code概述 vscode是一种简化且高效的代码编辑器&#xff0c;同时支持诸如调试&#xff0c;任务执行和版本管…

人工智能 Day06 pandas库进阶

1.处理缺失数据 总体流程是这样的&#xff0c; 归根在于如何处理NAN&#xff0c;接下来详细赘述 1.1. 处理缺失值的相关函数 判断缺失值 pd.isnull(df)&#xff1a;用于判断 DataFrame df 中的元素是否为缺失值&#xff08;NaN &#xff09;&#xff0c;返回一个与df 形状相同…

【Tools】Visual Studio Code安装保姆级教程(2025版)

00. 目录 文章目录 00. 目录01. Visual Studio Code概述02. Visual Studio Code下载03. Visual Studio Code安装04. Visual Studio Code配置05. 附录 01. Visual Studio Code概述 Visual Studio Code&#xff08;简称 VS Code&#xff09;是由微软开发的一款免费、开源且跨平台…

14.使用各种读写包操作 Excel 文件:辅助模块

一 各种读写包 这些是 pandas 在底层使用的各种读写包。无须安装 pandas&#xff0c;直接使用这些读写包就能够读写 Excel 工作簿。可以尽可能地使用 pandas 来解决这类问题&#xff0c;只在 pandas 没有提供你所需要的功能时才用到读写包。 表中没有 xlwings &#xff0c;因为…

AI赋能实时安全背带监测解决方案

背景&#xff1a;安全背带检测的行业刚需与技术痛点 在建筑施工、石油化工、仓储物流等高危行业中&#xff0c;安全背带是保障作业人员生命安全的最后一道防线。据统计&#xff0c;超过30%的高空坠落事故与未正确佩戴安全背带直接相关。传统依赖人工巡检的监督方式存在效率低、…

神聖的綫性代數速成例題2. 行列式的性質

性質 1&#xff1a;行列式與它的轉置行列式相等&#xff1a; 設為行列式&#xff0c;為其轉置行列式&#xff0c;則。 性質 2&#xff1a;交換行列式的兩行 (列)&#xff0c;行列式變號&#xff1a; 若行列式經過交換第行和第行得到行列式&#xff0c;則。 性質 3&#xff…

大模型推理 memory bandwidth bound (3) - MLA

系列文章目录 大模型推理 & memory bandwidth bound (1) - 性能瓶颈与优化概述 大模型推理 & memory bandwidth bound (2) - Multi-Query Attention 大模型推理 & memory bandwidth bound (3) - MLA 文章目录 系列文章目录前言一、原理1.低秩压缩 & 动机2.矩阵…

CTP开发爬坑指北(九)

CTP API开发中有很多需要注意的小细节&#xff0c;稍有不慎就会出问题&#xff0c;不然&#xff0c;轻则表现与预期不符&#xff0c;重则程序崩溃影响策略盈利。本系列将容易遇到的坑列出来&#xff0c;以供开发时参考&#xff0c;如有疑义之处&#xff0c;欢迎指正。 在国内期…

python_巨潮年报pdf下载

目录 前置&#xff1a; 步骤&#xff1a; step one: pip安装必要包&#xff0c;获取年报url列表 step two: 将查看url列表转换为pdf url step three: 多进程下载pdf 前置&#xff1a; 1 了解一些股票的基本面需要看历年年报&#xff0c;在巨潮一个个下载比较费时间&…

量化交易backtrader实践(五)_策略综合篇(3)_经典策略复盘

01_经典策略复盘 在某款股票软件手机版App上&#xff0c;有一项“复盘”的功能&#xff0c;这个功能很强大&#xff0c;它能把这支股票近1年的走势&#xff0c;用设置好的六个策略去回测&#xff0c;得到每个策略的近一年的收益率&#xff0c;并做了从最好到最差的排序。这就能…

蓝桥与力扣刷题(蓝桥 字符统计)

题目&#xff1a;给定一个只包含大写字母的字符出 S, 请你输出其中出现次数最多的字符。如果有多个字母均出现了最多次, 按字母表顺序依次输出所有这些字母。 输入格式 一个只包含大写字母的字等串 S. 输出格式 若干个大写字母&#xff0c;代表答案。 样例输入 BABBACAC样…

protobuf安装

安装 github官方链接 https://github.com/protocolbuffers/protobuf/ 以protobuf21为例 https://github.com/protocolbuffers/protobuf/releases/download/v21.11/protobuf-all-21.11.zip windows 解压好文件夹后,使用cmake,vs,qt creator等工具打开该项目,进行编译,编译需…

Compose 实践与探索八 —— LayoutModifier 解析

前面几节讲的 Modifier 都是起辅助作用的&#xff0c;比如 Modifier 的伴生对象、CombinedModifier、 ComposedModifier 以及几乎所有 Modifier 的父接口 Modifier.Element。本篇我们开始讲具有直接功效的 Modifier&#xff0c;分为几个大类&#xff1a;LayoutModifier、DrawMo…

stl之string的详解

一&#xff0c;string定义的方式 &#xff0c;string定义了多种函数重载的方式&#xff0c;常用的构造函数如下&#xff1a; string(); string(const string& str); string(const string& str, size_t pos, size_t len npos); string(const char* s); string(const …