252、适配器 bind
 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 对象调用
 它。
 }
 253、可变函数和参数
 写一个函数,函数的参数是函数对象及参数,功能和 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();
 }
 254、回调函数的实现
 在消息队列和网络库的框架中,当接收到消息(报文)时,回调用户自定义的函数对象,把消息(报
 文)参数传给它,由它决定如何处理。
 示例:
 #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++学习笔记(23)
2025/11/4 9:47:59 
来源:https://blog.csdn.net/qq_60098634/article/details/142252029 
浏览: 
次
 
关键词:C++学习笔记(23)
版权声明:
本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。
我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com
热文排行
- 老外讲解用Delphi 12.3作web
 - 数据库物理结构设计
 - 华为 海思22AP10(SS524)H.265 编解码处理器用户指南
 - 基于重要抽样的主动学习不平衡分类方法ALIS
 - 开源模型时代的 AI 开发革命:Dify 技术深度解析
 - npm install puppeteer 报错 npm ERR! PUPPETEER_DOWNLOAD_HOST is deprecated解决办法
 - 【量化策略】均值回归策略
 - 《缺失MRI模态下的脑肿瘤分割的潜在相关表示学习》| 文献速递-深度学习肿瘤自动分割
 - 如何在 Mac 上清空硬盘后恢复丢失的数据?
 - (2)Django生产环境数据库的切换以及环境配置python-dotenv方案
 
