包装器function
std::function模板类是一个通用的可调用对象的包装器,用简单的、统一的方式处理可调用对象。
template<class _Fty>
class function……
_Fty是可调用对象的类型,格式:返回类型(参数列表)。
包含头文件:#include <functional>
注意:
重载了bool运算符,用于判断是否包装了可调用对象。
如果std::function对象未包装可调用对象,使用std::function对象将抛出std::bad_function_call异常。
示例:
#include <iostream>
#include <functional>
using namespace std;// 普通函数
void show(int bh, const string& message) {cout << "亲爱的" << bh << "," << message << endl;
}struct AA // 类中有静态成员函数。
{static void show(int bh, const string& message) {cout << "亲爱的" << bh << "," << message << endl;}
};struct BB // 仿函数。
{void operator()(int bh, const string& message) {cout << "亲爱的" << bh << "," << message << endl;}
};struct CC // 类中有普通成员函数。
{void show(int bh, const string& message) {cout << "亲爱的" << bh << "," << message << endl;}
};struct DD // 可以被转换为普通函数指针的类。
{using Fun = void (*)(int, const string&); // 函数指针的别名。operator Fun() {return show; // 返回普通函数show的地址。}
};int main()
{using Fun = void(int, const string&); // 函数类型的别名。// 普通函数。void(*fp1)(int, const string&) = show; // 声明函数指针,指向函数对象。fp1(1, "我是一只傻傻鸟。"); // 用函数指针调用普通函数。function<void(int, const string&)> fn1 = show; // 包装普通全局函数show。fn1(1, "我是一只傻傻鸟。"); // 用function对象调用普通全局函数show。// 类的静态成员函数。void(*fp3)(int, const string&) = AA::show; // 用函数指针指向类的静态成员函数。fp3(2, "我是一只傻傻鸟。"); // 用函数指针调用类的静态成员函数。function<void(int, const string&)> fn3 = AA::show; // 包装类的静态成员函数。fn3(2, "我是一只傻傻鸟。"); // 用function对象调用类的静态成员函数。// 仿函数。BB bb;bb(3, "我是一只傻傻鸟。"); // 用仿函数对象调用仿函数。function<void(int, const string&)> fn4 = BB(); // 包装仿函数。fn4(3, "我是一只傻傻鸟。"); // 用function对象调用仿函数。// 创建lambda对象。auto lb = [](int bh, const string& message) {cout << "亲爱的" << bh << "," << message << endl;};lb(4, "我是一只傻傻鸟。"); // 调用lambda函数。function<void(int, const string&)> fn5 = lb; // 包装lamba函数。fn5(4, "我是一只傻傻鸟。"); // 用function对象调用lamba函数。// 类的非静态成员函数。CC cc;void (CC:: * fp11)(int, const string&) = &CC::show; // 定义类成员函数的指针。(cc.*fp11)(5, "我是一只傻傻鸟。"); // 用类成员函数的指针调用类的成员函数。function<void(CC&,int, const string&)> fn11 = &CC::show; // 包装成员函数。fn11(cc,5, "我是一只傻傻鸟。"); // 用function对象调用成员函数。// 可以被转换为函数指针的类对象。DD dd;dd(6, "我是一只傻傻鸟。"); // 用可以被转换为函数指针的类对象调用普通函数。function<void(int, const string&)> fn12 = dd; // 包装可以被转换为函数指针的类。fn12(6, "我是一只傻傻鸟。"); // 用function对象调用它。function<void(int, const string&)> fx=dd;try {if (fx) fx(6, "我是一只傻傻鸟。");}catch (std::bad_function_call e) {cout << "抛出了std::bad_function_call异常。";}
}
std::bind()模板函数是一个通用的函数适配器(绑定器),它用一个可调用对象及其参数,生成一个新的可调用对象,以适应模板。
包含头文件:#include <functional>
函数原型:
template< class Fx, class... Args >
function<> bind (Fx&& fx, Args&...args);
Fx:需要绑定的可调用对象(可以是前两节课介绍的那六种,也可以是function对象)。
args:绑定参数列表,可以是左值、右值和参数占位符std::placeholders::_n,如果参数不是占位符,缺省为值传递,std:: ref(参数)则为引用传递。
std::bind()返回std::function的对象。
std::bind()的本质是仿函数。
示例一(bind的基本用法):
#include <iostream>
#include <functional>
using namespace std;// 普通函数
void show(int bh, const string& message) {cout << "亲爱的" << bh << "号," << message << endl;
}int main()
{function<void(int, const string&)> fn1 = show;function<void(int, const string&)> fn2 = bind(show, placeholders::_1, placeholders::_2);fn1(1, "我是一只傻傻鸟。");fn2(1, "我是一只傻傻鸟。");function<void(const string&, int)> fn3 = bind(show, placeholders::_2, placeholders::_1);fn3("我是一只傻傻鸟。", 1);function<void(const string&)> fn4 = bind(show, 3, placeholders::_1);fn4("我是一只傻傻鸟。");function<void(int, const string&,int)> fn5 = bind(show, placeholders::_1, placeholders::_2);fn5(1, "我是一只傻傻鸟。", 88);
}
示例二(绑定六种可调用对象):
#include <iostream>
#include <functional>
using namespace std;// 普通函数
void show(int bh, const string& message) {cout << "亲爱的" << bh << "," << message << endl;
}struct AA // 类中有静态成员函数。
{static void show(int bh, const string& message) {cout << "亲爱的" << bh << "," << message << endl;}
};struct BB // 仿函数。
{void operator()(int bh, const string& message) {cout << "亲爱的" << bh << "," << message << endl;}
};struct CC // 类中有普通成员函数。
{void show(int bh, const string& message) {cout << "亲爱的" << bh << "," << message << endl;}
};struct DD // 可以被转换为普通函数指针的类。
{using Fun = void (*)(int, const string&); // 函数指针的别名。operator Fun() {return show; // 返回普通函数show的地址。}
};int main()
{// 普通函数。function<void(int, const string&)> fn1 = bind(show, placeholders::_1, placeholders::_2); // 绑定普通全局函数show。fn1(1, "我是一只傻傻鸟。"); // 用function对象调用普通全局函数show。// 类的静态成员函数。function<void(int, const string&)> fn3 = bind(AA::show, placeholders::_1, placeholders::_2); // 绑定类的静态成员函数。fn3(2, "我是一只傻傻鸟。"); // 用function对象调用类的静态成员函数。// 仿函数。function<void(int, const string&)> fn4 = bind(BB(), placeholders::_1, placeholders::_2); // 绑定仿函数。fn4(3, "我是一只傻傻鸟。"); // 用function对象调用仿函数。// 创建lambda对象。auto lb = [](int bh, const string& message) {cout << "亲爱的" << bh << "," << message << endl;};function<void(int, const string&)> fn5 = bind(lb, placeholders::_1, placeholders::_2); // 绑定lamba函数。fn5(4, "我是一只傻傻鸟。"); // 用function对象调用lamba函数。// 类的非静态成员函数。CC cc;//function<void(CC&, int, const string&)> fn11 = bind(&CC::show, placeholders::_1, placeholders::_2, placeholders::_3); // 绑定成员函数。//fn11(cc, 5, "我是一只傻傻鸟。"); // 用function对象调用成员函数。function<void(int, const string&)> fn11 = bind(&CC::show,&cc,placeholders::_1, placeholders::_2); // 绑定成员函数。fn11(5, "我是一只傻傻鸟。"); // 用function对象调用成员函数。// 可以被转换为函数指针的类对象。DD dd;function<void(int, const string&)> fn12 = bind(dd, placeholders::_1, placeholders::_2); // 绑定可以被转换为函数指针的类。fn12(6, "我是一只傻傻鸟。"); // 用function对象调用它。
}
写一个函数,函数的参数是函数对象及参数,功能和thread类的构造函数相同。
示例:
#include <iostream>
#include <thread>
#include <functional>
using namespace std;void show0() { // 普通函数。cout << "亲爱的,我是一只傻傻鸟。\n";
}void show1(const string& message) { // 普通函数。cout << "亲爱的," << message << endl;
}struct CC // 类中有普通成员函数。
{void show2(int bh, const string& message) {cout << "亲爱的" << bh << "号," << message << endl;}
};template<typename Fn, typename...Args>
auto show(Fn&& fn, Args&&...args) -> decltype(bind(forward<Fn>(fn), forward<Args>(args)...))
{cout << "表白前的准备工作......\n";auto f = bind(forward<Fn>(fn), forward<Args>(args)...);f();cout << "表白完成。\n";return f;
}int main()
{show(show0);show(show1,"我是一只傻傻鸟。");CC cc;auto f = show(&CC::show2,&cc, 3,"我是一只傻傻鸟。");f();//thread t1(show0);//thread t2(show1,"我是一只傻傻鸟。");//CC cc;//thread t3(&CC::show2,&cc, 3,"我是一只傻傻鸟。");//t1.join();//t2.join();//t3.join();
}
在消息队列和网络库的框架中,当接收到消息(报文)时,回调用户自定义的函数对象,把消息(报文)参数传给它,由它决定如何处理。
示例:
#include <iostream>
#include <string>
#include <thread> // 线程类头文件。
#include <mutex> // 互斥锁类的头文件。
#include <deque> // deque容器的头文件。
#include <queue> // queue容器的头文件。
#include <condition_variable> // 条件变量的头文件。
#include <functional>
using namespace std;void show(const string& message) { // 处理业务的普通函数cout << "处理数据:" << message << endl;
}struct BB { // 处理业务的类void show(const string& message) {cout << "处理表白数据:" << message << endl;}
};class AA
{mutex m_mutex; // 互斥锁。condition_variable m_cond; // 条件变量。queue<string, deque<string>> m_q; // 缓存队列,底层容器用deque。function<void(const string&)> m_callback; // 回调函数对象。
public:// 注册回调函数,回调函数只有一个参数(消费者接收到的数据)。template<typename Fn, typename ...Args>void callback(Fn && fn, Args&&...args) {m_callback = bind(forward<Fn>(fn), forward<Args>(args)..., std::placeholders::_1); // 绑定回调函数。}void incache(int num) // 生产数据,num指定数据的个数。{lock_guard<mutex> lock(m_mutex); // 申请加锁。for (int ii = 0; ii < num; ii++){static int bh = 1; // 超女编号。string message = to_string(bh++) + "号超女"; // 拼接出一个数据。m_q.push(message); // 把生产出来的数据入队。}//m_cond.notify_one(); // 唤醒一个被当前条件变量阻塞的线程。m_cond.notify_all(); // 唤醒全部被当前条件变量阻塞的线程。}void outcache() { // 消费者线程任务函数。while (true) {// 把互斥锁转换成unique_lock<mutex>,并申请加锁。unique_lock<mutex> lock(m_mutex);// 1)把互斥锁解开;2)阻塞,等待被唤醒;3)给互斥锁加锁。m_cond.wait(lock, [this] { return !m_q.empty(); });// 数据元素出队。string message = m_q.front(); m_q.pop();cout << "线程:" << this_thread::get_id() << "," << message << endl;lock.unlock(); // 手工解锁。// 处理出队的数据(把数据消费掉)。if (m_callback) m_callback(message); // 回调函数,把收到的数据传给它。}}
};int main()
{AA aa;// aa.callback(show); // 把普通函数show()注册为回调函数。BB bb;aa.callback(&BB::show, &bb); // 把类成员函数BB::show()注册为回调函数。thread t1(&AA::outcache, &aa); // 创建消费者线程t1。thread t2(&AA::outcache, &aa); // 创建消费者线程t2。thread t3(&AA::outcache, &aa); // 创建消费者线程t3。this_thread::sleep_for(chrono::seconds(2)); // 休眠2秒。aa.incache(2); // 生产2个数据。this_thread::sleep_for(chrono::seconds(3)); // 休眠3秒。aa.incache(5); // 生产5个数据。t1.join(); // 回收子线程的资源。t2.join();t3.join();
}
C++虚函数在执行过程中会跳转两次(先查找对象的函数表,再次通过该函数表中的地址找到真正的执行地址),这样的话,CPU会跳转两次,而普通函数只跳转一次。
CPU每跳转一次,预取指令要作废很多,所以效率会很低。(百度)
为了管理的方便(基类指针可指向派生类对象和自动析构派生类),保留类之间的继承关系。
示例:
#include <iostream> // 包含头文件。
#include <functional>
using namespace std;struct Hero { // 英雄基类//virtual void show() { cout << "英雄释放了技能。\n"; }function<void()> m_callback; // 用于绑定子类的成员函数。// 注册子类成员函数,子类成员函数没有参数。template<typename Fn, typename ...Args>void callback(Fn&& fn, Args&&...args) {m_callback = bind(forward<Fn>(fn), forward<Args>(args)...);}void show() { m_callback(); } // 调用子类的成员函数。
};struct XS :public Hero { // 西施派生类void show() { cout << "西施释放了技能。\n"; }
};struct HX :public Hero { // 韩信派生类void show() { cout << "韩信释放了技能。\n"; }
};int main()
{// 根据用户选择的英雄,施展技能。int id = 0; // 英雄的id。cout << "请输入英雄(1-西施;2-韩信。):";cin >> id;// 创建基类指针,将指向派生类对象,用基类指针调用派生类的成员函数。Hero* ptr = nullptr;if (id == 1) { // 1-西施ptr = new XS;ptr->callback(&XS::show, static_cast<XS*>(ptr)); // 注册子类成员函数。}else if (id == 2) { // 2-韩信ptr = new HX;ptr->callback(&HX::show, static_cast<HX*>(ptr)); // 注册子类成员函数。}if (ptr != nullptr) {ptr->show(); // 调用子类的成员函数。delete ptr; // 释放派生类对象。}
}
相关文章:
包装器function
std::function模板类是一个通用的可调用对象的包装器,用简单的、统一的方式处理可调用对象。 template<class _Fty> class function…… _Fty是可调用对象的类型,格式:返回类型(参数列表)。 包含头文件:#include <functi…...
Django Rest_Framework(三)
文章目录 1. 认证Authentication2. 权限Permissions使用提供的权限举例自定义权限 3. 限流Throttling基本使用可选限流类 4. 过滤Filtering5. 排序Ordering6. 分页Pagination可选分页器 7. 异常处理 ExceptionsREST framework定义的异常 8. 自动生成接口文档coreapi安装依赖设置…...
总结 IO、存储、硬盘、文件系统相关常识
目录 一、IO是什么? 二、存储 三、硬盘 四、文件系统 4.1 文件目录和组织方式 4.2 文化路径 4.3 文件类型 4.4 文件系统操作 一、IO是什么? IO是英文Input/Output的缩写,指输入/输出。在计算机科学中,IO通常指计算机与外部设备或…...
JavaScript、深入浅出Node.js前端技能汇总
JavaScript 前端技能汇总 Frontend Knowledge Structure 深入浅出Node.js 书籍pdf 《深入浅出Node.js》的相关代码 Javascript&jQuery教程 pdf html & css教程 pdf 高性能JavaScript_中英双语版 pdf 跳坑之js调用另一个js文件中函数 方法1; 在html文件中加入两…...
use gnustep objective-c
first app #import <Foundation/Foundation.h>int main(int argc, const char * argv[]) {NSAutoreleasePool *pool [NSAutoreleasePool new];NSLog("first start");[pool drain];return 0; }tech 专注于概念,而不是迷失在语言技术细节中编程语言…...
8.15锁的优化
1.锁升级(锁膨胀) 无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁 偏向锁:不是真的加锁,而是做了一个标记,如果有别的线程来竞争才会真的加锁,如果没有别的线程竞争就不会加锁. 轻量级锁:一个线程占领锁资源后,另一个线程通过自旋的方式反复确认锁是否被是否(这个过程比较…...
单片机复位电路分析
来分析一下这个电路: 首先这里面有电容,所以是一个动态电路。哈哈哈 假设左上角的电压源是5V的代号为VOLT。 可以知道电容capacitor C1左边的电压也是5V,电容中间隔着一个绝缘体,所以不导电, 这个时候电流无法通过…...
公文写作技巧:“三面镜子”写作提纲60例
写作技巧:“三面镜子”写作提纲60例 1. 用好“三面镜子” 推深做实警示教育 勤用“反光镜”以案为鉴。 善用“显微镜”以案明纪。 巧用“聚光镜”以案促改。 2. 年轻干部要用好“三面镜子” 用好“反光镜”,照亮基层中的“暗点” 用好“显微镜”&am…...
useEffect中的函数会执行2次原因
一、useEffect介绍 useEffect是React18的新特性,表示React的生命周期Hooks组件。等价于Claas组件的componentDidMount、componentDidUpdate,useEffect的返回函数等价于componentWillUnmount。(组件卸载、重新挂载都会触发这个函数,…...
更新k8s环境支付系统支付证书
目录 一、背景 二、更新支付系统银行证书 三、备份旧的secret信息 四、更新支付应用的证书信息 五、重启支付系统的应用 六、验证应用实例挂载的秘钥已更新 一、背景 支付系统是基于k8s容器化部署的微服务,支付系统使用的支付证书以及和银行有关的证书都是保存…...
C#的yield
在 C# 中,yield 关键字用于定义迭代器方法(Iterator Methods),并使其返回一个可枚举的序列。通过使用 yield 关键字,可以简化迭代器的实现,使其更加直观和易于理解。 使用 yield 关键字定义的方法被称为迭…...
外卖多门店小程序开源版开发
外卖多门店小程序开源版开发 外卖多门店小程序开源版的开发可以按照以下步骤进行: 确定需求:明确外卖多门店小程序的功能和特点,包括用户注册登录、浏览菜单、下单支付、订单管理等。技术选型:选择适合开发小程序的技术框架&…...
打印图案、
描述 请编写一个程序,打印下面的图案: 输入 无 输出 打印上述图案 输入样例 1 无 输出样例 1 * * * * * * * * * * * * * * * * * * * * * * * * * 代码一(如下):直接输出 #include <iostream> usin…...
# Windows 环境下载 Android 12源码
前言 Android 官网(该方式不适合 Windows 平台):https://source.android.com/source/downloading.html (备注自 2021 年 6 月 22 日起,安卓操作系统不再支持在 Windows 或 MacOS 上进行构建,如果要编译源码推荐先安装…...
【运维面试】Docker技术面试题总结
【运维面试】Docker技术面试题总结 一、Docker的基础概念1.1 什么是Docker?它可以为我们提供哪些便利?1.2 Docker的优点是什么?1.3 Docker的镜像是什么?1.4 Docker的数据卷是什么?1.5 Docker Compose是什么?1.6 Docker Swarm是什么?1.7 Docker Hub是什么?有哪些用途?1…...
CNN成长路:从AlexNet到EfficientNet(01)
一、说明 在 10年的深度学习中,进步是多么迅速!早在 2012 年,Alexnet 在 ImageNet 上的准确率就达到了 63.3% 的 Top-1。现在,我们超过90%的EfficientNet架构和师生训练(teacher-student)。 如果我们在 Ima…...
使用IDEA操作Mysql数据库
idea中自带了关于数据库的连接 首先要确保你的MySQL正在运行中 打开idea找到database( view —> Tool Windows —> database),大家也可以定个快捷键,方便以后日常操作 就是这个样子,然后点加号 然后就可以编写执…...
ChatGPT下架官方检测工具,承认无法鉴别AI内容
去年底,OpenAI 推出的 ChatGPT ,带来了生成式人工智能涌现的热潮。它不仅能够协助完成撰写邮件、视频脚本、文案、翻译、代码等任务,还能通过学习和理解人类的语言来进行对话,并根据聊天的上下文进行互动。 但随之而来的争议也让人…...
Java通过实例调用getClass()方法、类名.class操作、通过运行时类获取其它信息
说明 Java Object类的getClass()函数,是通过对象调用的,是一个实例方法,该方法返回当前对象的运行时类。 通过类名.class可以获得和通过实例调用getClass()函数一样的信息。 获得运行时类以后,可以进一步获取其它信息。 代码示例…...
UE5+Paperzd问题
TopDown的2D游戏,遇到两个问题,第一问题是游戏一开始就会从tilemap上掉下去。第二个问题是没法和图层2上的物体做碰撞。 一、碰撞问题 1、创建的TileSet后,左侧选中一个tile后,一定要点击上边的Add Box,否则创建出来的…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...
Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...
前端开发者常用网站
Can I use网站:一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use:Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站:MDN JavaScript权威网站:JavaScript | MDN...
