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> | 逻辑或 | `a | b` |
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> | 按位或 | `a | b` |
bit_xor<T> | 按位异或 | a ^ b | |
bit_not<T> | 按位取反(C++14) | ~a |
