C++中`std::function`和`std::bind`的详细解析

news/2025/11/1 17:18:49/文章来源:https://www.cnblogs.com/I989809/p/19183581

一、核心概念

1. std::function

  • 功能:通用函数包装器,可存储任意可调用对象
  • 特点
    • 类型擦除:统一处理函数指针、lambda、成员函数等
    • 运行时有少量性能开销
    • 声明时需要指定函数签名

2. std::bind

  • 功能:绑定参数生成新可调用对象
  • 特点
    • 参数绑定和参数顺序调整
    • 支持占位符(_1_2等)
    • 可绑定成员函数和对象指针

二、基础用法示例

1. std::function声明与使用

#include <functional>// 声明函数类型
std::function<int(int, int)> math_op; // 绑定普通函数
int add(int a, int b) {return a + b; }
math_op = add;
cout << math_op(2, 3);  // 输出5// 绑定lambda表达式
math_op = [](int x, int y) {return x * y; };
cout << math_op(2, 3);  // 输出6// 绑定成员函数
class Calculator {public:int sub(int a, int b) {return a - b; }
};
Calculator calc;
math_op = std::bind(&Calculator::sub, &calc, std::placeholders::_1, std::placeholders::_2);
cout << math_op(5, 2);  // 输出3

2. std::bind参数绑定

using namespace std::placeholders;void print_sum(int a, int b, int c) {std::cout << a + b + c << '\n';
}// 绑定固定参数
auto f1 = std::bind(print_sum, 10, _1, _2);
f1(20, 30);  // 输出60(10+20+30)// 调整参数顺序
auto f2 = std::bind(print_sum, _3, _2, _1);
f2(10, 20, 30);  // 输出60(30+20+10)// 绑定引用参数
int counter = 0;
auto inc = std::bind([](int& c) {c++; }, std::ref(counter));
inc();
cout << counter;  // 输出1

三、应用场景

1. 回调机制

class Button {std::function<void()> onClick;
public:void setCallback(std::function<void()> cb) {onClick = cb;}void click() {if(onClick) onClick();}
};Button btn;
btn.setCallback([](){cout << "Button clicked!"; });
btn.click();

2. 策略模式

class DataProcessor {std::function<void(std::vector<int>&)> strategy;
public:void setStrategy(std::function<void(std::vector<int>&)> s) {strategy = s;}void process(std::vector<int>& data) {if(strategy) strategy(data);}
};// 使用不同处理策略
DataProcessor dp;
dp.setStrategy([](auto& d) {/* 加密策略 */ });
dp.process(data);

3. 函数适配器

// 将成员函数适配为自由函数
class Logger {public:void write(const string& msg) {cout << "[LOG] " << msg << endl;}
};Logger logger;
auto logFunc = std::bind(&Logger::write, &logger, _1);// 统一接口调用
void systemOutput(const string& msg, std::function<void(const string&)> output) {output("System: " + msg);
}systemOutput("Started", logFunc);

四、高级用法

1. 组合绑定

using namespace std::placeholders;double complex_calc(int a, double b, const string& c) {return a * b + stod(c);
}auto bind_calc = std::bind(complex_calc, _2, 3.14, _1);
double result = bind_calc("9.8", 2);  // 2 * 3.14 + 9.8 = 16.08

2. 绑定重载函数

class Overloaded {public:void func(int) {cout << "int\n"; }void func(double) {cout << "double\n"; }
};Overloaded obj;
auto f = std::bind(static_cast<void(Overloaded::*)(int)>(&Overloaded::func), &obj, _1);
f(10);  // 输出int

3. 绑定智能指针

class Service {public:void handleRequest(int id) {/* ... */ }
};auto service = std::make_shared<Service>();
auto handler = std::bind(&Service::handleRequest, service, _1);// 保证对象生命周期
handler(1001);
 

五、注意事项

1. 生命周期管理

std::function<void()> createCallback() {int local = 42;// return [&](){ cout << local; };  // 危险!局部变量将销毁return [=](){cout << local; };     // 正确:值捕获
}

2. 性能考量

  • std::function调用比直接函数调用慢约2-3倍
  • 小对象建议使用lambda,大对象使用std::ref

3. 类型安全

std::function<void(int)> f = [](string s){};  // 编译错误!参数类型不匹配
 

六、与Lambda表达式对比

特性 std::bind Lambda表达式
参数绑定 显式使用placeholders 自动捕获外部变量
成员函数绑定 需要显式指定对象指针 捕获this即可
可读性 复杂参数绑定时较难理解 结构清晰直观
闭包大小 通常较大(存储绑定参数) 由捕获变量决定
内联优化 较少优化机会 编译器更容易优化

推荐实践

// 优先使用Lambda
auto f = [x](int a, int b) {return x + a * b; };// 需要复杂参数绑定时使用bind
auto bound = std::bind(&Class::method, obj_ptr, _1, 42);
 

七、现代C++改进

1. 通用Lambda(C++14)

auto generic_lambda = [](auto x, auto y) {return x + y; };
std::function<int(int,int)> f = generic_lambda;

2. 模板参数推导(C++17)

std::function f = [](){/* ... */ };  // C++17起支持推导

3. std::invoke(C++17)

template<typename Callable>
void execute(Callable&& c) {std::invoke(std::forward<Callable>(c));
}

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

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

相关文章

k8s-应用部署和组件及常用命令(2)

1、相关组件介绍: node是k8s的集群节点,和实际的机器对应 pod是应用容器,不同的应用部署在不同的pod中,k8s协调资源,将pod部署到集群中的node节点上(非master节点)。 同时pod又是挂在namespace下面的,命名空间…

高级语言程序设计第3次作业

2025高级语言程序设计 https://edu.cnblogs.com/campus/fzu/gjyycx/homework/13574 102500426康凯帆 书本第4章4.8编程练习题目中的第2题第4题,第6题第8题 Fan.: 11-01 16:45:16Fan.: 11-01 16:45:17Fan.: 11-01 16:4…

C++多线程相关应用

一、多线程基础 1. 线程创建与管理 #include <thread> #include <iostream>void task(int id) {std::cout << "Thread " << id << " executing\n"; }int main() {s…

CSP-J 2025 复赛解析

[CSP-J 2025] 拼数 / number 题目描述(Description) 小 R 正在学习字符串处理。小 X 给了小 R 一个字符串 \(s\),其中 \(s\) 仅包含小写英文字母及数字,且包含至少一个 \(1 \sim 9\) 中的数字。小 X 希望小 R 使用 \…

加速 Docker 镜像下载的神器:KSpeeder 上手体验

身为开发者,相信你也遇到过拉取 Docker 镜像时的“龟速”折磨——尤其从 Docker Hub 下载热门镜像时,几十 KB/s 的速度让人怀疑人生。最近我在浏览器里看到 KSpeeder 这款工具,专门解决 Docker 镜像加速问题,便顺手…

Java桌面应用开发:JavaFX模块化与响应式

一、技术选型对比1.1 JavaFXJavaFX 是 Oracle 推出的新一代 Java 桌面应用开发框架,具有以下特点: 现代 UI 设计:支持 CSS 样式、3D 效果和动画丰富的控件库:包含 TableView、WebView 等高级组件FXML 分离设计:界…

MyBatis 动态标签

配置文件示例 #应用程序名称 spring.application.name=configuration #应用程序端口号 server.port=8080 #数据库连接信息 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/database_name?characterEncoding=utf8…

用 CSS Grid 实现高效布局的 3 个实战技巧

1. 动态网格:auto-fit + minmax() 响应式适配 无需媒体查询!一行代码创建自适应列: .grid-container {display: grid;grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); } auto-fit:自动填充可用空间…

【Linux 高效的系统】文件系统与软硬件连接

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Webpack技术深度解析:模块打包与性能优化

在前端开发的浩瀚星空中,Webpack无疑是一颗璀璨的明星。作为现代前端工程不可或缺的一部分,Webpack以其强大的模块打包能力和高度的灵活性,赢得了广大开发者的青睐。本文将深入探讨Webpack的核心概念、配置优化以及…

Pinely Round 5 (Div. 1 + Div. 2) A+B+C+D

A.Round Trip原题链接 解题思路简单贪心模拟一下,能减则减AC code void solve(){int r,x,d,n;cin>>r>>x>>d>>n;string s;cin>>s;s="&"+s;int ans=0;for(int i=1;i<=n;…

Spring Web MVC入门 - 指南

Spring Web MVC入门 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", …

CSS:现代Web设计的不同技术

CSS(层叠样式表)是为HTML提供样式的主要语言。随着Web的发展,CSS也不断演进,融入了许多新特性和技术,帮助开发者创建更美观和功能丰富的网站。本文将探讨CSS的几种不同技术,包括Flexbox、Grid、动画效果、预处理…

左手坐标系和右手坐标系

左手坐标系和右手坐标系1. 左手坐标系 伸开左手,掌心向外,拇指和食指垂直,弯曲中指、无名指和小指。拇指所指的方向是X轴正方向,食指所指的方向是Y轴正方形,中指、无名指和小指所指的方向是Z轴正方向。 2. 右手坐…

ubuntu24 主题体验经验

一、主题来源网站 https://www.gnome-look.org/s/Gnome/browse?cat=135&page=11&ord=rating 二、主题安装文件夹 & 设置创建文件夹 ~/.themes 下载的主题直接扔到这个文件夹。好处有2 (1) 简单,不用权…

图神经网络(GNN)

一、概念 1、GNN是处理图结构数据的深度学习模型,核心是通过图卷积、注意力机制等操作,让节点学习自身与邻居的关联信息,最终输出节点 / 图的特征或预测结果 2、传统深度学习(CNN、RNN)擅长处理网格数据(如图片)…

docker部署OpenResume 开源简历生成器

采用现代专业设计,符合美国最佳实践,并与 Greenhouse 和 Lever 等主流 ATS 平台兼容。它能自动设置字体、字号、页边距和项目符号格式,确保一致性并避免人为错误。官网:GitHub - xitanggg/open-resume: OpenResume…

深入解析:MySQL 配置管理与日志系统完全指南:从基础到高级优化

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

不使用 AAudio 的前提下,降低 Android 音频传输延时的方案

如果芯片厂未实现 MMAP 驱动接口,那么即使客户端代码调用了 AAudio 接口,也无法降低音频传输延时。因为 AAudio 会回退到以 legacy 模式工作。在芯片驱动不支持使用 AAudio 的前提下,我们可以通过其它方式来减少音频…

深入解析:dmfldr快速装载工具使用

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …