三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

C++仿函数以及STL内置仿函数

C++仿函数以及STL内置仿函数

仿函数又称函数对象,本质是重载了operator()运算符的类的对象,可以和普通函数一样被调用。

一、仿函数基础概念

1. 什么是仿函数

仿函数不是函数,而是一个类类型的对象。当我们给这个对象加上()调用运算符时,它会触发类中重载的operator(),从而实现类似函数的行为。

最简单的仿函数示例

#include <iostream> using namespace std; // 定义仿函数类 struct Add { // 重载函数调用运算符 int operator()(int a, int b) const { return a + b; } }; int main() { Add add; // 创建仿函数对象 cout << add(3, 5) << endl; // 像函数一样调用,输出8 cout << Add()(10, 20) << endl; // 临时对象调用,输出30 return 0; }

2. 仿函数的核心优势(为什么不用普通函数?)

仿函数解决了普通函数和函数指针的诸多局限性,是 STL 首选的可调用对象形式:

特性普通函数函数指针仿函数
携带状态❌ 只能通过全局变量❌ 只能通过全局变量✅ 可以作为类成员变量存储状态
性能可内联❌ 间接调用,无法内联✅ 编译器可直接内联operator()
类型安全❌ 类型擦除,易出错✅ 每个仿函数都是独立类型
泛型支持✅ 完美适配模板元编程
可组合性✅ 可通过适配器灵活组合

3. 仿函数的分类

根据operator()接受的参数个数,仿函数分为:

  • 一元仿函数:接受 1 个参数,如negate<int>
  • 二元仿函数:接受 2 个参数,如plus<int>
  • 多元仿函数:C++11 后支持,但 STL 内置仿函数最多二元

二、STL 内置仿函数全解

STL 在<functional>头文件中提供了一套完整的通用仿函数,覆盖了所有基础运算,无需我们重复编写。它们都是模板类,可以适配任意数值类型。

1. 算术运算仿函数

用于执行基本的算术计算,全部是二元仿函数(除了negate是一元)。

仿函数功能等价表达式
plus<T>加法a + b
minus<T>减法a - b
multiplies<T>乘法a * b
divides<T>除法a / b
modulus<T>取模a % b
negate<T>取反(一元)-a

使用示例

#include <vector> #include <algorithm> #include <functional> using namespace std; int main() { vector<int> a = {1, 2, 3, 4}; vector<int> b = {10, 20, 30, 40}; vector<int> c(4); // 两个数组对应元素相加 transform(a.begin(), a.end(), b.begin(), c.begin(), plus<int>()); // c = {11, 22, 33, 44} // 所有元素取反 transform(a.begin(), a.end(), a.begin(), negate<int>()); // a = {-1, -2, -3, -4} return 0; }

2. 关系运算仿函数

用于比较两个值的大小关系,全部是二元仿函数,返回bool类型。

仿函数功能等价表达式
equal_to<T>等于a == b
not_equal_to<T>不等于a != b
less<T>小于a < b
greater<T>大于a > b
less_equal<T>小于等于a <= b
greater_equal<T>大于等于a >= b

高频使用场景

#include <vector> #include <algorithm> #include <functional> using namespace std; int main() { vector<int> v = {3, 1, 4, 1, 5, 9}; // 降序排序(默认是less<int>()升序) sort(v.begin(), v.end(), greater<int>()); // v = {9, 5, 4, 3, 1, 1} // 统计大于5的元素个数 int cnt = count_if(v.begin(), v.end(), bind(greater<int>(), placeholders::_1, 5)); // cnt = 1 return 0; }

⚠️面试重点std::sort默认使用less<T>(),实现升序排列;std::map/std::set默认也使用less<T>作为比较器,保证元素按升序存储。

3. 逻辑运算仿函数

用于执行布尔逻辑运算,返回bool类型。

仿函数功能等价表达式
logical_and<T>逻辑与a && b
logical_or<T>逻辑或`ab`
logical_not<T>逻辑非(一元)!a

使用示例

#include <vector> #include <algorithm> #include <functional> using namespace std; int main() { vector<int> v = {1, 6, 12, 18, 25}; // 查找大于5且小于20的第一个元素 auto it = find_if(v.begin(), v.end(), [](int x) { return logical_and<int>()(greater<int>()(x, 5), less<int>()(x, 20)); }); // it指向6 return 0; }

4. 位运算仿函数(C++11 新增)

用于执行整数的位运算。

仿函数功能等价表达式
bit_and<T>按位与a & b
bit_or<T>按位或`ab`
bit_xor<T>按位异或a ^ b
bit_not<T>按位取反(C++14)~a
← 返回列表