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

std::reference_wrapper 和 std::function的详细介绍

关于 std::reference_wrapperstd::function 的详细介绍及具体测试用例:


1. std::reference_wrapper(引用包装器)

核心功能
  • 包装引用:将引用转换为可拷贝、可赋值的对象
  • 支持隐式转换:可自动转换为原始引用类型
  • 容器友好:允许在 STL 容器中存储引用(原生 C++ 数组引用无法直接存入容器)
典型应用场景
  • 在容器中存储大型对象的引用(避免拷贝)
  • 需要传递引用的模板元编程场景
  • 配合算法使用引用语义(如 std::for_each 修改原集合)
测试用例
#include <functional>
#include <vector>
#include <algorithm>
#include <iostream>void modify(int& x) {x *= 2;
}int main() {// 场景1:容器存储引用int a = 10, b = 20, c = 30;std::vector<std::reference_wrapper<int>> nums = {a, b, c};// 通过引用修改原始值for (auto& ref : nums) ref.get() += 5;std::cout << "修改后: " << a << ", " << b << ", " << c << "\n";// 输出: 修改后: 15, 25, 35// 场景2:配合算法使用std::for_each(nums.begin(), nums.end(), modify);std::cout << "算法处理: " << a << ", " << b << ", " << c << "\n";// 输出: 算法处理: 30, 50, 70// 场景3:隐式转换int& original_ref = nums[0]; // 自动转换为 int&original_ref = 100;std::cout << "隐式转换后: " << a << "\n"; // 输出: 100return 0;
}

2. std::function(通用函数包装器)

核心功能
  • 类型擦除:统一存储各种可调用对象(函数指针、lambda、成员函数等)
  • 延迟执行:将函数作为参数传递或返回值
  • 运行时多态:动态绑定不同函数实现
典型应用场景
  • 回调函数机制(如事件处理)
  • 命令模式实现
  • 动态策略模式
测试用例
#include <functional>
#include <iostream>
#include <string>// 普通函数
void greet(const std::string& name) {std::cout << "Hello, " << name << "!\n";
}// 函数对象
struct Farewell {void operator()(const std::string& name) const {std::cout << "Goodbye, " << name << "!\n";}
};class Person {
public:void setName(const std::string& name) {m_name = name;}void showName() const {std::cout << "My name is " << m_name << "\n";}
private:std::string m_name;
};int main() {// 包装普通函数std::function<void(const std::string&)> func1 = greet;func1("Alice"); // 输出: Hello, Alice!// 包装函数对象Farewell farewell;std::function<void(const std::string&)> func2 = farewell;func2("Bob"); // 输出: Goodbye, Bob!// 包装 lambdaauto lambda = [](const std::string& s) { std::cout << "Lambda: " << s << "\n"; };std::function<void(const std::string&)> func3 = lambda;func3("Charlie"); // 输出: Lambda: Charlie// 包装成员函数Person person;person.setName("David");// 绑定成员函数(需要对象实例)std::function<void()> func4 = std::bind(&Person::showName, &person);func4(); // 输出: My name is David// 包装带参数的成员函数std::function<void(const std::string&)> func5 = std::bind(&Person::setName, &person, std::placeholders::_1);func5("Eve");person.showName(); // 输出: My name is Eve// 空函数检查std::function<void()> empty_func;if (!empty_func) {std::cout << "空函数对象\n"; // 会执行}return 0;
}

3. 关键对比总结

特性std::reference_wrapperstd::function
主要用途包装引用,实现引用语义的容器存储统一管理各种可调用对象
类型安全性强类型(模板参数指定类型)通过函数签名约束(如 void(int)
性能影响零开销(编译时解析)有运行时开销(类型擦除)
典型操作get(), 隐式转换operator(), bool 转换检查

4. 使用注意事项

(1) reference_wrapper
  • 不能包装临时对象(悬挂引用风险)

  • 不能替代智能指针(不管理生命周期)

  • auto 配合时需注意类型推导:

    auto ref = std::ref(a); // 类型是 reference_wrapper<int>
    int& r = ref;           // 需要显式转换或使用 get()
    
(2) std::function
  • 空状态检查:调用空 function 会抛出 std::bad_function_call

  • 性能关键场景慎用(相比虚函数有额外开销)

  • 存储成员函数时需绑定对象实例:

    // 正确做法
    std::function<void()> f = std::bind(&Class::method, &obj);
    

5. 进阶用法示例

事件系统(std::function 应用)
#include <functional>
#include <vector>class Button {
public:using Callback = std::function<void()>;void addClickListener(Callback cb) {listeners.push_back(cb);}void click() {for (auto& cb : listeners) {if (cb) cb();}}private:std::vector<Callback> listeners;
};// 使用示例
void playSound() { /* ... */ }int main() {Button btn;btn.addClickListener([] { std::cout << "点击事件1\n"; });btn.addClickListener(playSound);btn.click(); // 触发所有回调return 0;
}

总结

  • reference_wrapper
    当需要容器存储引用或模板需要推导引用类型时使用,避免不必要的拷贝。
  • std::function
    当需要统一处理不同类型的回调函数或实现运行时多态时使用,为现代 C++ 回调系统的核心组件。

两者结合使用可以构建灵活高效的抽象机制,例如在事件系统中用 reference_wrapper 传递对象引用,用 std::function 管理事件处理方法。

相关文章:

std::reference_wrapper 和 std::function的详细介绍

关于 std::reference_wrapper 和 std::function 的详细介绍及具体测试用例&#xff1a; 1. std::reference_wrapper&#xff08;引用包装器&#xff09; 核心功能 包装引用&#xff1a;将引用转换为可拷贝、可赋值的对象支持隐式转换&#xff1a;可自动转换为原始引用类型容器…...

如何封装一个上传文件组件

#今天用el-upload感到很多不方便&#xff0c;遂决定自己封装一个。注&#xff1a;本文不提供表面的按钮样式和文件上传成功后的样式&#xff0c;需要自己创建。本文仅介绍逻辑函数# 1&#xff0c;准备几个表面用来指引上传的元素 2&#xff0c;创造统一的隐藏文件上传输入框&…...

MySQL-5.7.37安装配置(Windows)

1.下载MySQL-5.7.37软件包并解压 2.配置本地环境变量 打开任务栏 搜索高级系统设置 新建MySQL的环境变量 然后在path中添加%MYSQL_HOME%\bin 3.在MySQL-5.7.37解压的文件夹下新建my.ini文件并输入以下内容 [mysqld]#端口号port 3306#mysql-5.7.27-winx64的路径basedirC:\mysq…...

CentOS与Ubuntu命令对比指南:从软件包管理到系统配置

CentOS与Ubuntu命令对比指南 作为两大主流Linux发行版,**CentOS(基于RHEL)和Ubuntu(基于Debian)**在日常运维中常因命令差异引发混淆。本文通过关键场景对比,助您快速掌握两者的核心操作区别。 一、软件包管理:yum/dnf vs apt 操作CentOSUbuntu更新软件源yum check-upd…...

鸿蒙北向应用开发:deveco 5.0 kit化文件相关2

鸿蒙北向应用开发:deveco 5.0 kit化文件相关 在kit化时,有时候会出现这样一种场景即你想把已有的d.ts导出换个名字,这样从名字上更贴合你的kit聚合 什么意思呢?比如现在有 ohos.hilog.d.ts 导出了hilog,现在你想kit化hilog,使得hilog导出名字为usrhilog,这样用户在使用你的k…...

《HelloGitHub》第 108 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对开源感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、…...

C++可变参数

可变参数C风格的可变参数C风格可变参数的使用 C11可变参数模板递归展开参数包参数列表展开折叠表达式 STL中的emplace插入接口 可变参数 C风格的可变参数 可变参数是一种语言特性&#xff0c;可以在函数声明中使用省略号...来表示函数接受可变数量的参数。 例如典型的printf…...

光传输设备现状

随着运营商准备好其基础设施以应对新一代高带宽应用程序和 AI 部署&#xff0c;光传输网络 (OTN) 市场再次有望实现稳健增长。 隧道的尽头有光亮&#xff0c;OTN 市场在 2024 年最后一个季度表现强劲&#xff0c;设备供过于求的时代已经结束。 供应商表示设备订单量有所增加&…...

Python 笔记 (二)

Python Note 2 1. Python 慢的原因2. 三个元素3. 标准数据类型4. 字符串5. 比较大小: 富比较方法 rich comparison6. 数据容器 (支持*混装* )一、允许重复类 (list、tuple、str)二、不允许重复类 (set、dict)1、集合(set)2、字典(dict)3、特殊: 双端队列 deque 三、数据容器的共…...

nt!IopCompleteReques函数分析之IopUpdateOtherTransferCount和IopDequeueThreadIrp

VOID IopCompleteRequest( IN PKAPC Apc, IN PKNORMAL_ROUTINE *NormalRoutine, IN PVOID *NormalContext, IN PVOID *SystemArgument1, IN PVOID *SystemArgument2 ) 第一部分&#xff1a; if (irp->UserEvent) { (VOID) KeSetEvent( …...

d2025329

目录 一、修复表中名字 二、患某种疾病的患者 三、最长连续子序列 四、二叉树的层序遍历 一、修复表中名字 1667. 修复表中的名字 - 力扣&#xff08;LeetCode&#xff09; concat(A,B)&#xff0c;将字符串A和B拼接left(str,len)&#xff0c;从字符串左边开始截取len个字…...

北斗导航 | 中国北斗卫星导航系统的发展历程——“三步走”战略:背景,信号频点,调制方式,短报文,等

中国北斗卫星导航系统的发展历程按照“三步走”战略逐步推进,从区域服务到全球覆盖,形成了北斗一号、北斗二号、北斗三号三代系统的迭代升级,展现了中国航天科技的自主创新与突破。以下是各阶段的核心内容与发展特点综述:一、北斗一号:中国卫星导航的奠基(1994-2003年) …...

cordova android12+升级一些配置注意事项

1.以android13为例 Cordova Android 13.0.0 cordova platform remove android cordova platform add android13.0.0Cordova Android 13.0.0 这里建议将android-studio升级到最新 build时若是需要到gradled安装失败 建议多试几次 或者直接用网页下载 找到 Android Studio 的 G…...

批量处理word里面表格的空白行

1&#xff0c;随便打开一个word文档。 2&#xff0c;按下Alt F11 VBA编辑器,在左侧的「工程资源管理器」窗口中找到Normal 项目,右键选择插入->模块。 弹出一下弹窗 3&#xff0c;输入一下代码 代码&#xff1a; Sub RemoveEmptyTableRows()Dim tbl As TableDim row As R…...

K8S学习之基础五十七:部署代码扫描工具sonarqube

部署代码扫描工具sonarqube 拉取postgres、sonarqube镜像&#xff0c;在harbor上创建postgres、sonarqube项目&#xff0c;将镜像上传至harbordocker pull postgres docker pull sonarqube docker tat postgres:latest 172.16.80.140/postgres/postgres:latest docker tat sona…...

Nginx 解决具有不安全、不正确或缺少 SameSite 属性的 Cookie方案

针对Nginx中Cookie的SameSite属性配置问题&#xff0c;以下是综合解决方案及注意事项&#xff1a; 一、基础配置方法 全局设置Cookie属性‌&#xff08;适用于Nginx直接生成Cookie&#xff09; 在nginx.conf的location块中通过add_header指令添加&#xff1a; add_header Se…...

音频知识 参数分析

通道布局 参考 通过pcm音频数据计算分贝 理解FFT和信号加窗原理及意义 dts音效大师教程...

使用 rsync 进行服务器文件同步与优化

使用 Rsync 工具在两台 Linux 服务器之间同步文件 Rsync 是一种高效的文件同步工具&#xff0c;它可以在本地或远程服务器之间同步文件和目录。Rsync 通过仅传输文件的变化部分来减少数据传输量&#xff0c;因此特别适合用于定期备份或同步大量数据。本文将详细介绍如何将 A 服…...

MySQL 的 SQL 语句执行顺序

MySQL 的 SQL 语句执行顺序并不完全按照代码的书写顺序执行&#xff0c;而是遵循一套固定的逻辑流程 1. FROM 和 JOIN 作用&#xff1a;确定查询的数据来源&#xff0c;包括表和它们的连接方式&#xff08;如 INNER JOIN, LEFT JOIN 等&#xff09;。 细节&#xff1a; 先执行…...

小型水库大坝安全及水雨情监测技术方案

一、小型水库监测系统构成 小型水库雨水情测报和大坝安全监测系统由水库监测站点、通信网络和监测平台等组成&#xff0c;系统总体架构如图所示。 水库监测站点设施包括&#xff1a;雨量计、水位计、视频监视设备、渗压计、量水堰计、变形监测仪器、数据采集仪、遥测终端、水准…...

scala简介和基础语法

Scala简介 Scala 是一门多范式&#xff08;multi-paradigm&#xff09;的编程语言&#xff0c;设计初衷是要集成面向对象编程和函数式编程的各种特性。 Scala 运行在 Java 虚拟机上&#xff0c;并兼容现有的 Java 程序。Scala 源代码被编译成 Java 字节码&#xff0c;所以它可…...

‘无法定位程序输入点kernel32.dll’详细的修复方法,一键快速修复kernel32.dll

在 Windows 系统运行过程中&#xff0c;若程序提示“无法定位程序输入点 kernel32.dll”&#xff0c;往往意味着程序调用了 kernel32.dll 中不存在或已变更的函数接口。作为系统的核心动态链接库&#xff0c;kernel32.dll 承担着内存管理、进程控制、文件操作等底层功能&#x…...

电源系统的热设计与热管理--以反激式充电器为例

前言 反激电源常用于各种电子设备中&#xff0c;比如充电器、适配器等&#xff0c;它们通过变压器进行能量转换。高温环境可能对电子元件造成影响&#xff0c;特别是像MOSFET、二极管、变压器这样的关键部件&#xff0c;导致效率变低&#xff0c;甚至可能导致功能失效。还有安…...

笔记本电脑更换主板后出现2203:System configuration is invalid,以及2201、2202系统错误的解决

笔记本电脑更换主板后启动出现2203:System configuration is invalid,以及2201、2202系统错误的解决 自用的一台ThinkpadT490笔记本电脑 ,由于主板故障,不得不更换主板,通过某宝购置主板后进行了更换。 具体拆卸笔记本可搜索网络视频教程。 注意: 在更换主板时,注意先拍…...

项目-苍穹外卖(十七) Apache POI+导出数据

一、介绍 二、入门案例 package com.sky.test;import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.File; import java.io.FileNotFoundException; import jav…...

蓝桥杯单片机刷题——E2PROM记录开机次数

设计要求 使用E2PROM完成数据记录功能&#xff0c;单片机复位次数记录到E2PROM的地址0中。每复位一次数值加1&#xff0c;按下按键S4&#xff0c;串口发送复位次数。串口发送格式如下&#xff1a; Number&#xff1a;1 备注&#xff1a; 单片机IRC振荡器频率设置为12MHz。 …...

聚合根的特性

聚合根的特性 聚合根是实体&#xff0c;拥有实体的业务属性和行为&#xff0c;同时也是聚合的管理者&#xff0c;负责协调聚合内的实体和值对象&#xff0c;按照固定的业务规则&#xff0c;完成业务逻辑。 聚合根是聚合对外唯一的接口人&#xff0c;聚合之间以聚合根ID关联的方…...

基于盛科CTC7132交换机核心模块

简介 基于盛科CTC7132 SOC方案构建&#xff0c;通过板对板高速连接器引出32路10G SerDes接口、1路PCIex1、2路管理SGMII接口、3路Uart接口&#xff08;1路调试串口2路功能串口&#xff09;、4路I2C接口(2路SOC部分2路PPU部分)、5路SMI接口&#xff08;1路管理口4路业务口&…...

How to install OpenJ9 JDK 17 on Ubuntu 24.04

概述 OpenJ9 是一款由 IBM 开发并开源的 Java 虚拟机&#xff08;JVM&#xff09;&#xff0c;现由 ​Eclipse 基金会管理&#xff08;名为 ​Eclipse OpenJ9&#xff09;。它旨在提供高性能、低内存消耗和快速启动时间&#xff0c;特别适用于云原生和容器化环境。 关键特性 …...

【即插即用涨点模块-卷积】SPDConv空间深度卷积,助力小目标与低分辨有效涨点【附源码+注释】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...