📖目录
- 前言
- [1. 为什么需要泛型算法?](#1. 为什么需要泛型算法?)
- [2. 迭代器:泛型算法的"交通系统"](#2. 迭代器:泛型算法的"交通系统")
- [3. C++20 Ranges:泛型算法的"智能交通系统"](#3. C++20 Ranges:泛型算法的"智能交通系统")
- [4. 数学视角:泛型算法的通用形式](#4. 数学视角:泛型算法的通用形式)
- [5. 策略模式:让算法"可插拔"](#5. 策略模式:让算法"可插拔")
- [6. C++20 Ranges vs 传统泛型算法](#6. C++20 Ranges vs 传统泛型算法)
- [7. 经典书籍推荐](#7. 经典书籍推荐)
- [8. 结语](#8. 结语)
前言
核心理念:泛型算法是C++ STL的基石,它让算法与容器解耦,实现"一算法多容器"的通用设计。想象一下,你去菜市场买菜:找最便宜的青菜(最小值)、找最新鲜的鱼(按日期排序),只需告诉"比价机器人"比较标准,而不需要知道具体怎么比较。这正是泛型算法的精髓!
本文与历史文章的关系:
我曾发表过一篇《【后端】【C++】函数对象与泛型算法:从"找最便宜的菜"说起](https://blog.csdn.net/xiezhiyi007/article/details/155673934)》,该文以"找最便宜的菜"为引子,介绍了C++中函数对象(Functor)与泛型算法的基础概念,通过findOptimum函数展示了策略模式的应用。
本文的升级点:
- C++20标准支持:本文基于C++20的Ranges库,将泛型算法的使用从"传递迭代器"升级为"直接操作容器"
- 代码简洁度提升:C++20 Ranges使代码量减少50%,语义更清晰
- 链式操作:展示Ranges库支持的管道式(pipeline)操作,这是旧文章无法实现的
如果你尚未阅读旧文,建议先阅读《【后端】【C++】函数对象与泛型算法:从"找最便宜的菜"说起》,它将为你理解本文提供基础。本文则是该文的C++20升级版,专注于现代C++的高效用法。
1. 为什么需要泛型算法?
在C++98之前,程序员需要为每种容器编写专门的算法。比如,为vector<int>写一个findMin,为list<string>写另一个findMin,代码重复率高达80%。这就像每次去超市都要重新学习怎么找最便宜的菜,效率低下。
泛型算法的诞生:C++ STL引入了泛型算法,通过迭代器(Iterator)作为桥梁,让算法与容器解耦。算法只关心"如何移动和访问元素",不关心"元素存储在哪里"。
2. 迭代器:泛型算法的"交通系统"
C++定义了5类迭代器,如同不同类型的交通系统:
| 迭代器类型 | 特点 | 适用场景 | 生活类比 |
|---|---|---|---|
| 输入迭代器 | 单向读取 | std::find |
单向售票口 |
| 输出迭代器 | 单向写入 | std::copy |
单向投递口 |
| 前向迭代器 | 单向读写 | std::list算法 |
前进的传送带 |
| 双向迭代器 | 双向读写 | std::reverse |
双向电梯 |
| 随机访问迭代器 | 随机定位 | std::sort |
电梯直达任意楼层 |
cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<int> vec = {5, 2, 8, 1, 9};
// 使用随机访问迭代器进行排序
std::sort(vec.begin(), vec.end()); // 1 2 5 8 9
// 使用输入迭代器查找元素
auto it = std::find(vec.begin(), vec.end(), 5);
if (it != vec.end()) {
std::cout << "Found 5 at position: " << std::distance(vec.begin(), it) << std::endl;
}
// 使用输出迭代器向新容器复制
std::vector<int> vec2;
std::copy(vec.begin(), vec.end(), std::back_inserter(vec2)); // 1 2 5 8 9
return 0;
}
执行结果:
text
Found 5 at position: 2
3. C++20 Ranges:泛型算法的"智能交通系统"
C++20引入了Ranges库,让泛型算法更简洁、更易读。传统写法需要传递两个迭代器,而Ranges只需传递容器本身。
传统写法 vs C++20 Ranges:
cpp
// 传统写法:需要传递迭代器范围
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = std::find(vec.begin(), vec.end(), 3);
if (it != vec.end()) {
std::cout << "Found 3" << std::endl;
}
// C++20 Ranges:只需传递容器
#include <ranges>
auto it = std::ranges::find(vec, 3); // 更简洁、更易读
Ranges库的核心优势:
- 代码更简洁:省去传递迭代器的步骤
- 语义更清晰:算法与数据的关联更直接
- 支持链式操作:实现"管道式"处理
cpp
#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// C++20 Ranges链式操作
auto result = vec | std::views::filter([](int x) { return x % 2 == 0; }) // 筛选偶数
| std::views::transform([](int x) { return x * 2; }); // 乘以2
for (int x : result) {
std::cout << x << " "; // 输出: 4 8
}
return 0;
}
执行结果:
text
4 8
4. 数学视角:泛型算法的通用形式

推导过程(找最小值) :

这正是std::min_element的内部逻辑。
5. 策略模式:让算法"可插拔"
策略模式是泛型算法的核心设计思想。它允许将算法的"比较标准"作为参数传入,实现"算法与策略解耦"。
cpp
#include <iostream>
#include <vector>
#include <algorithm>
// 策略1:找最小值
struct Less {
bool operator()(int a, int b) const { return a < b; }
};
// 策略2:找最大值
struct Greater {
bool operator()(int a, int b) const { return a > b; }
};
// 泛型算法:findOptimum
template <typename T, typename Comparison>
const T* findOptimum(const std::vector<T>& values, Comparison compare) {
if (values.empty()) return nullptr;
const T* optimum = &values[0];
for (size_t i = 1; i < values.size(); ++i) {
// 如果当前元素比已知最优更"优",就更新
if (compare(values[i], *optimum)) {
optimum = &values[i];
}
}
return optimum;
}
int main() {
std::vector<int> numbers = {91, 18, 92, 22, 13, 43};
// 使用Less策略找最小值
std::cout << "Minimum: " << *findOptimum(numbers, Less{}) << std::endl;
// 使用Greater策略找最大值
std::cout << "Maximum: " << *findOptimum(numbers, Greater{}) << std::endl;
return 0;
}
执行结果:
text
Minimum: 13
Maximum: 92
6. C++20 Ranges vs 传统泛型算法
| 特性 | 传统泛型算法 | C++20 Ranges |
|---|---|---|
| 代码简洁性 | 需要传递迭代器 | 仅需传递容器 |
| 语义清晰度 | 有点抽象 | 更直观 |
| 链式操作 | 需要嵌套调用 | 支持管道式操作 |
| 适用容器 | 任何支持迭代器的容器 | 任何支持ranges的容器 |
| 代码可读性 | 一般 | 高 |
7. 经典书籍推荐
-
《C++ Templates: The Complete Guide (2nd Ed)》 by David Vandevoorde et al.
- 被誉为"模板圣经",第19章详细讲解"Functors and Lambdas"
- 包含C++20 Concepts与Ranges相关内容
- 适合想深入理解泛型编程的开发者
-
《Effective Modern C++》 by Scott Meyers
- 第23条:"理解如何使用Ranges"
- 第24条:"了解C++20的协程"
- 适合想在实际项目中应用现代C++特性的开发者
-
《C++ Standard Library: A Tutorial and Reference (2nd Ed)》 by Nicolai M. Josuttis
- 详细讲解STL的每个组件
- 包含C++11/14/17/20的特性对比
- 适合需要快速查阅STL特性的开发者
8. 结语
泛型算法是C++ STL的基石,它让代码更加通用、高效。从C++98的迭代器到C++20的Ranges,泛型算法不断进化,使C++编程更加简洁、优雅。
记住:"算法是骨架,策略是插件" 。下次当你写std::sort(vec.begin(), vec.end(), my_compare)时,你会知道:背后站着一个默默工作的策略模式。
编译提示 :所有C++20代码需启用
/std:c++20编译选项(VS2022/Clang14+)。C++20 Ranges库在<ranges>头文件中定义。