在 C++20 中,Ranges 与 Concepts 两大特性相互配合,为泛型编程带来了全新的语义与效率。本文将从两者的基本概念出发,阐述它们如何共同简化代码、提升可读性,并通过示例演示如何在实际项目中将它们结合使用。
1. 何为 Range?
Range 是一种抽象的序列概念,它封装了一组可迭代元素,并提供统一的接口进行访问。相比传统的 begin()/end(),Range 让“序列”成为一个可组合、可链式操作的对象。
- Iterator 与 Sentinel:C++20 中的 Range 用
iterator与sentinel两个概念来定义边界,而非传统的end()。 - View:是对 Range 的不可变变换(如
filter,transform,take等)。 - Adapter:可用于构造新的 Range 或 View。
#include <ranges>
#include <vector>
#include <iostream>
std::vector <int> data = {1, 2, 3, 4, 5, 6};
auto even = data | std::views::filter([](int x){ return x % 2 == 0; });
for (int v : even) std::cout << v << ' '; // 输出 2 4 6
2. Concepts 的核心
Concepts 允许我们对模板参数进行约束,提升模板的可读性与错误信息的准确性。通过 requires 关键字,可以在编译阶段检查传入类型是否满足某些属性。
template<typename T>
concept Integral = std::is_integral_v <T>;
template<Integral T>
T add(T a, T b) { return a + b; }
3. Range 与 Concept 的结合
C++20 将 Range 与 Concept 结合,形成了 Range Concepts。通过 std::ranges::range 这个 Concept,我们可以确保一个类型真正是可迭代的,并在编译期得到验证。
3.1 只要满足 Range 就能使用算法
#include <ranges>
#include <algorithm>
template<std::ranges::range R>
auto sum(R&& r) {
return std::accumulate(std::ranges::begin(r), std::ranges::end(r), 0);
}
3.2 通过 View 进行链式组合
#include <ranges>
#include <vector>
#include <numeric>
#include <iostream>
std::vector <int> nums = {1, 2, 3, 4, 5, 6};
auto result = std::views::filter(nums, [](int x){ return x % 2 == 0; }) // 过滤偶数
| std::views::transform([](int x){ return x * x; }) // 平方
| std::ranges::to<std::vector>(); // 转成 vector
for (int v : result) std::cout << v << ' '; // 输出 4 16 36
4. 性能收益
- 懒加载(Lazy evaluation):View 在使用前不执行任何操作,只有在需要迭代时才进行计算。
- 避免中间容器:通过链式调用,可以避免生成多余的临时容器,减少拷贝与内存分配。
- 编译时优化:Concepts 让编译器能够更准确地推导类型,进而进行更深入的优化。
5. 实战:实现一个通用的 map 函数
下面给出一个基于 Range 与 Concepts 的 map 实现,兼顾可读性与性能。
#include <ranges>
#include <utility>
template<std::ranges::range R, typename F>
auto map(R&& r, F&& f) {
// 返回一个 transform view,延迟执行
return std::views::transform(std::forward <R>(r), std::forward<F>(f));
}
使用示例:
std::vector <int> numbers = {1, 2, 3, 4};
auto squares = map(numbers, [](int n){ return n * n; });
for (int v : squares) std::cout << v << ' '; // 1 4 9 16
6. 小结
- Range 提供了统一的序列抽象,支持链式变换与懒加载。
- Concepts 在编译期对模板进行约束,提升代码安全性与错误可读性。
- 两者结合 使得泛型代码既简洁又高效,成为现代 C++ 的强大工具。
从 C++20 开始,合理使用 Ranges 与 Concepts 能显著提升项目的可维护性和运行性能。希望本文能帮助你快速上手,并在日常编码中充分发挥这两项特性的优势。