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

C++ STL 仿函数完全指南:从内置仿函数到自定义实现

引言

在前面的 STL 系列中,我们多次用到greater<int>()less<int>()这样的写法,它们就是仿函数(Functor)。仿函数不是函数,而是重载了operator()的类对象,可以像函数一样被调用。

STL 内置了大量开箱即用的仿函数,分为算术运算关系比较逻辑运算三大类。它们广泛用于sortpriority_queueset/map等需要自定义行为的场景。

第一部分:仿函数基础

一、为什么需要仿函数

// 普通函数:不能保存状态 bool cmp(int a, int b) { return a > b; } // 仿函数:可以保存状态 struct Cmp { int threshold; Cmp(int t) : threshold(t) {} bool operator()(int a, int b) const { return (a > threshold) && (b > threshold); } }; Cmp cmp(10); cout << cmp(15, 12) << endl; // true cout << cmp(5, 3) << endl; // false
对比函数指针仿函数Lambda
保存状态
内联优化❌ 难
类型明确✅ 强匿名
C++ 版本所有所有C++11+

第二部分:STL 内置仿函数

STL 内置仿函数都在<functional>头文件中。

一、算术类仿函数

仿函数作用示例
plus<T>加法plus<int>()(3,5)→ 8
minus<T>减法minus<int>()(5,3)→ 2
multiplies<T>乘法multiplies<int>()(3,5)→ 15
divides<T>除法divides<int>()(6,3)→ 2
modulus<T>取模modulus<int>()(7,3)→ 1
negate<T>取反(单目)negate<int>()(5)→ -5
#include <iostream> #include <functional> using namespace std; int main() { plus<int> add; cout << add(3, 5) << endl; // 8 cout << plus<int>()(10, 20) << endl; // 30(匿名对象) negate<int> neg; cout << neg(5) << endl; // -5 modulus<int> mod; cout << mod(10, 3) << endl; // 1(10 % 3) return 0; }

二、关系类仿函数

仿函数作用示例
equal_to<T>等于==equal_to<int>()(3,3)→ true
not_equal_to<T>不等于!=not_equal_to<int>()(3,5)→ true
greater<T>大于>greater<int>()(5,3)→ true
greater_equal<T>大于等于>=greater_equal<int>()(5,5)→ true
less<T>小于<less<int>()(3,5)→ true
less_equal<T>小于等于<=less_equal<int>()(3,3)→ true
#include <iostream> #include <functional> #include <set> #include <vector> #include <algorithm> using namespace std; int main() { // 1. sort 降序排列 vector<int> v = {3, 1, 4, 1, 5, 9}; sort(v.begin(), v.end(), greater<int>()); // 9 5 4 3 1 1 // 2. set 降序 set<int, greater<int>> s = {3, 1, 4, 1, 5}; // 5 4 3 1 // 3. priority_queue 小顶堆 priority_queue<int, vector<int>, greater<int>> pq; return 0; }

三、逻辑类仿函数

仿函数作用示例
logical_and<T>逻辑与&&logical_and<bool>()(true,false)→ false
logical_or<T>逻辑或||logical_or<bool>()(true,false)→ true
logical_not<T>逻辑非!logical_not<bool>()(true)→ false
#include <iostream> #include <functional> #include <vector> #include <algorithm> using namespace std; int main() { vector<bool> flags = {true, false, true, true}; // 统计 true 的数量 int cnt = count(flags.begin(), flags.end(), true); cout << cnt << endl; // 3 // 统计 false 的数量(用 logical_not 反转) cnt = count_if(flags.begin(), flags.end(), logical_not<bool>()); cout << cnt << endl; // 1 return 0; }

第三部分:常用场景

一、sort 排序

#include <algorithm> #include <vector> #include <functional> using namespace std; vector<int> v = {5, 2, 8, 1, 9}; sort(v.begin(), v.end()); // 默认 less,升序 sort(v.begin(), v.end(), less<int>()); // 升序,等价 sort(v.begin(), v.end(), greater<int>()); // 降序

二、set/map 自定义排序

// 降序 set set<int, greater<int>> s; // 降序 map map<int, string, greater<int>> m;

三、priority_queue 优先级

// 大顶堆(默认,less) priority_queue<int> pq1; // top 是最大值 // 小顶堆 priority_queue<int, vector<int>, greater<int>> pq2; // top 是最小值

四、transform 变换

#include <algorithm> #include <vector> #include <functional> using namespace std; vector<int> v1 = {1, 2, 3, 4, 5}; vector<int> v2(v1.size()); // 每个元素取反 transform(v1.begin(), v1.end(), v2.begin(), negate<int>()); // v2: -1 -2 -3 -4 -5 // 两个数组相加 transform(v1.begin(), v1.end(), v2.begin(), v2.begin(), plus<int>()); // v2: 0 0 0 0 0

第四部分:自定义仿函数

一、简单自定义

// 自定义比较:按绝对值排序 struct AbsCmp { bool operator()(int a, int b) const { return abs(a) < abs(b); } }; vector<int> v = {-5, 2, -8, 1, 9}; sort(v.begin(), v.end(), AbsCmp()); // 1 2 -5 -8 9

二、带状态的仿函数

// 删除小于阈值的元素 class LessThan { private: int threshold; public: LessThan(int t) : threshold(t) {} bool operator()(int x) const { return x < threshold; } }; vector<int> v = {5, 2, 8, 1, 9, 3}; // 删除小于 5 的元素 v.erase(remove_if(v.begin(), v.end(), LessThan(5)), v.end()); // 5 8 9

三、仿函数适配器(传统写法,了解即可)

// C++11 之前用 bind2nd 绑定第二个参数(已废弃) // 现代 C++ 建议用 Lambda 替代 vector<int> v = {5, 2, 8, 1, 9, 3}; auto it = find_if(v.begin(), v.end(), bind2nd(greater<int>(), 5)); // 找第一个大于 5 的元素 // 现代写法(推荐) auto it2 = find_if(v.begin(), v.end(), [](int x) { return x > 5; });

第五部分:仿函数 vs Lambda

// 需求:找第一个大于 5 的元素 // 方式1:仿函数 struct GreaterThan5 { bool operator()(int x) const { return x > 5; } }; auto it1 = find_if(v.begin(), v.end(), GreaterThan5()); // 方式2:Lambda(C++11,推荐) auto it2 = find_if(v.begin(), v.end(), [](int x) { return x > 5; });
对比仿函数Lambda
可复用性✅ 定义一次,随处用❌ 匿名,不能复用
类型明确✅ 有类名❌ 匿名类型
简洁性❌ 需要定义类✅ 一行搞定
适用场景多处复用的逻辑一次性使用的逻辑

推荐原则

  • 需要多处复用的逻辑(如greater<int>)→ 仿函数

  • 一次性使用的逻辑 → Lambda

  • 需要保存复杂状态→ 仿函数

总结

一、内置仿函数速查

类别仿函数用途
算术plusminusmultipliesdividesmodulusnegate算术运算
关系equal_tonot_equal_togreatergreater_equallessless_equal比较排序
逻辑logical_andlogical_orlogical_not逻辑操作

二、常用位置

sort(v.begin(), v.end(), greater<int>()); // 排序 set<int, greater<int>>; // 有序容器 priority_queue<int, vector<int>, greater<int>>; // 优先队列 transform(v1.begin(), v1.end(), v2.begin(), negate<int>()); // 变换

三、一句话记忆

STL 内置仿函数在<functional>中,分算术、关系、逻辑三类。它们本质是重载了operator()的类对象,主要用于sortset/mappriority_queuetransform等需要自定义行为的场景。可复用逻辑用仿函数,一次性用 Lambda。

http://www.gsyq.cn/news/1434789.html

相关文章:

  • 2026年武夷山正规酒店怎么选?这6家本地人推荐 - charlieruizvin
  • 增强PSO与集成学习优化医学图像分割:从聚类到深度学习的实践
  • Zotero Style插件高能进度条无法显示的深度解决方案
  • 工业平行宇宙:序章:虚拟工厂先试错1000遍,真实世界零风险起飞
  • 如何免费解锁123云盘VIP功能:三步实现高速下载体验
  • 到底为什么Node.js 或 Go 那样原生内置高性能的网络服务器引擎?
  • 高效实现百度网盘批量转存的BaiduPanFilesTransfers完整指南
  • 如何用kill-doc浏览器脚本免费下载30+平台文档?完整使用指南
  • 大模型求职必看:收藏这份分层准备指南,从新手到大厂Offer收割机
  • 国信中业—原位XPS(In-situ XPS)将“反应”和“测试”同步进行
  • Δ-Motif算法:GPU并行化子图同构匹配技术解析
  • Windows 11终极优化指南:如何用Win11Debloat一键清理系统垃圾和提升性能
  • LanzouAPI技术揭秘:如何通过PHP实现蓝奏云直链解析的高效方案
  • 不同场景下电动挡烟垂壁怎么选
  • PHP遇到报错,不只搜解决方案,要看 堆栈跟踪,读 源码。
  • .NET Windows Desktop Runtime:彻底解决Windows桌面应用部署难题的终极指南
  • WarcraftHelper:魔兽争霸3现代电脑完美运行终极指南
  • 杭州余杭永鸿再生资源:余杭区废旧金属回收公司 - LYL仔仔
  • 3秒隐形:Boss-Key如何让你的数字生活拥有“第二空间”
  • GlosSI终极指南:在Windows上实现系统级Steam控制器支持
  • PHP的打断点就是手动var_dump+exit?
  • 如何永久保存你的数字记忆:WeChatMsg终极指南
  • 保姆级教程:用davfs2在Ubuntu 22.04上挂载WebDAV网盘(含权限配置与开机自动挂载)
  • OBS高级计时器终极指南:6种专业模式掌控直播节奏
  • 佛山粤利通市政工程:麻章专业的路划线划线施工 - LYL仔仔
  • SQL示例:正确理解题意(隐藏分组键)严格SQL模式下,ORDER BY中的列必须出现在GROUP BY中或作为聚合函数
  • 紧凑型UWB-MIMO天线设计:高隔离度与三频带阻实现原理
  • 结构化输出与约束解码技术深度解析:从 JSON Schema 到受控文本生成的完整方法论
  • 3分钟搞定MASA模组全家桶汉化:Minecraft 1.21完整中文解决方案
  • 2026许昌市防水补漏公司权威推荐:卫生间、阳台、屋顶、地下室、飘窗、外墙漏水,专业防水公司TOP5口碑榜+全维度测评(2026年6月最新深度行业资讯) - 防水百科