C++ boost::range 详解:基于最新版本的现代范围处理指南

C++ boost::range 详解:基于最新版本的现代范围处理指南

  • [一、C++ boost::range 详解](#一、C++ boost::range 详解)
    • [1. 引言:为什么需要 boost::range?](#1. 引言:为什么需要 boost::range?)
    • [2、boost::range 核心概念](#2、boost::range 核心概念)
      • [2.1、 什么是 Range?](#2.1、 什么是 Range?)
      • [2.2、 Range 适配器与算法](#2.2、 Range 适配器与算法)
    • 3、安装与配置(基于最新版本)
      • 3.1、下载库
      • [3.2、Visual Studio新建工程](#3.2、Visual Studio新建工程)
      • [3. 3、将源码解压到工程目录下](#3. 3、将源码解压到工程目录下)
      • 3.4、添加路径
    • [4、基础用法:从 STL 算法到 Range 算法](#4、基础用法:从 STL 算法到 Range 算法)
      • [4.1 、直接替换 STL 算法](#4.1 、直接替换 STL 算法)
      • [4.2、 处理子范围](#4.2、 处理子范围)
    • [5、高级特性:Range 适配器](#5、高级特性:Range 适配器)
      • [5.1、 过滤(filtered)](#5.1、 过滤(filtered))
      • [5.2、 变换(transformed)](#5.2、 变换(transformed))
      • [5.3、 其他常用适配器](#5.3、 其他常用适配器)
    • [6、 实用工具函数](#6、 实用工具函数)
      • [6.1、 范围生成器](#6.1、 范围生成器)
      • [6.2 、连接多个范围](#6.2 、连接多个范围)
      • [6.3 、判断范围属性](#6.3 、判断范围属性)
    • 7、性能考虑与最佳实践
      • [7.1、 惰性求值的优势](#7.1、 惰性求值的优势)
      • [7.2、 何时复制 vs 何时使用视图](#7.2、 何时复制 vs 何时使用视图)
      • [7.3 、与 C++20 Ranges 的兼容性](#7.3 、与 C++20 Ranges 的兼容性)
    • [8、 实战示例:数据处理管道](#8、 实战示例:数据处理管道)
    • 9、总结
      • [9.1 、主要优势](#9.1 、主要优势)
      • [9.2、 适用场景](#9.2、 适用场景)
  • 二、代码示例

一、C++ boost::range 详解

1. 引言:为什么需要 boost::range?

在传统的 C++ STL 算法中,我们经常需要传递一对迭代器(begin/end)来指定操作范围:

cpp 复制代码
std::vector<int> vec = {1, 2, 3, 4, 5};
std::sort(vec.begin(), vec.end());  // 传统方式

这种方式虽然灵活,但存在几个明显问题:

  • 代码冗长 :每次都要写 begin()end()
  • 容易出错:begin/end 不匹配可能导致未定义行为
  • 缺乏组合性:难以将多个算法操作流畅地串联起来

boost::range 库正是为了解决这些问题而生。它提供了一种**范围(Range)**的抽象,将一对迭代器封装为单个对象,让代码更简洁、更安全、更具表现力。

2、boost::range 核心概念

2.1、 什么是 Range?

在 boost::range 中,一个 Range 就是任何可以获取到 begin()end() 迭代器的对象。这包括:

  • 所有 STL 容器(vector、list、map、set 等)
  • 原生数组
  • 字符串(std::string、C 风格字符串)
  • 迭代器对(std::pair<iterator, iterator>)
  • 以及任何自定义的满足 Range 概念的类型

2.2、 Range 适配器与算法

boost::range 提供了两大核心组件:

  1. Range 算法:STL 算法的 Range 版本,接受 Range 对象而非迭代器对
  2. Range 适配器:对现有 Range 进行变换,生成新的"视图"Range

3、安装与配置(基于最新版本)

3.1、下载库

访问链接https://www.boost.org/

3.2、Visual Studio新建工程

3. 3、将源码解压到工程目录下

新建一个main.cpp文件

将下载的压缩包解压到main.cpp同级目录,并改名为boost

3.4、添加路径

4、基础用法:从 STL 算法到 Range 算法

4.1 、直接替换 STL 算法

几乎所有 STL 算法都有对应的 boost::range 版本:

cpp 复制代码
#include <vector>
#include <iostream>
#include <boost/range/algorithm.hpp>

int main() {
    std::vector<int> numbers = {5, 2, 8, 1, 9, 3};
    
    // 传统 STL 方式
    std::sort(numbers.begin(), numbers.end());
    
    // boost::range 方式(更简洁)
    boost::sort(numbers);
    
    // 其他常用算法
    auto it = boost::find(numbers, 8);          // 查找元素
    bool has_three = boost::contains(numbers, 3); // 检查包含
    boost::reverse(numbers);                    // 反转
    
    // 输出结果
    boost::copy(numbers, std::ostream_iterator<int>(std::cout, " "));
    // 输出: 1 2 3 5 8 9
    
    return 0;
}

4.2、 处理子范围

cpp 复制代码
#include <boost/range/algorithm.hpp>
#include <boost/range/sub_range.hpp>

std::vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// 创建子范围(不复制数据)
auto sub = boost::make_iterator_range(vec.begin() + 2, vec.begin() + 7);
// sub 包含: {3, 4, 5, 6, 7}

// 对子范围排序
boost::sort(sub);
// 原 vec 变为: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

// 查找子范围中的元素
auto pos = boost::find(sub, 5);  // 返回指向 vec[4] 的迭代器

5、高级特性:Range 适配器

Range 适配器是 boost::range 最强大的功能之一,它们可以惰性地转换 Range,而不立即复制或计算所有元素。

5.1、 过滤(filtered)

cpp 复制代码
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/algorithm/copy.hpp>

std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// 过滤出偶数
auto even_numbers = numbers | boost::adaptors::filtered([](int n) {
    return n % 2 == 0;
});

// 惰性求值:此时尚未计算
std::cout << "偶数: ";
boost::copy(even_numbers, std::ostream_iterator<int>(std::cout, " "));
// 输出: 2 4 6 8 10

5.2、 变换(transformed)

cpp 复制代码
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <cmath>

std::vector<int> values = {1, 2, 3, 4, 5};

// 计算平方
auto squares = values | boost::adaptors::transformed([](int x) {
    return x * x;
});

std::cout << "平方: ";
boost::copy(squares, std::ostream_iterator<int>(std::cout, " "));
// 输出: 1 4 9 16 25

// 链式调用:先过滤再变换
auto result = values 
    | boost::adaptors::filtered([](int x) { return x > 2; })
    | boost::adaptors::transformed([](int x) { return std::sqrt(x); });

5.3、 其他常用适配器

cpp 复制代码
#include <boost/range/adaptors.hpp>

std::vector<std::pair<int, std::string>> pairs = {
    {1, "one"}, {2, "two"}, {3, "three"}
};

// 1. 取键(keys)
auto keys = pairs | boost::adaptors::map_keys;
// 包含: {1, 2, 3}

// 2. 取值(values)
auto values = pairs | boost::adaptors::map_values;
// 包含: {"one", "two", "three"}

// 3. 反转(reversed)
std::vector<int> vec = {1, 2, 3};
auto reversed = vec | boost::adaptors::reversed;
// 包含: {3, 2, 1}

// 4. 唯一化(uniqued)
std::vector<int> dup = {1, 2, 2, 3, 3, 3};
auto unique = dup | boost::adaptors::uniqued;
// 包含: {1, 2, 3}

// 5. 切片(sliced)
std::vector<int> nums = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
auto slice = nums | boost::adaptors::sliced(2, 7);
// 包含索引 [2, 7) 的元素: {2, 3, 4, 5, 6}

6、 实用工具函数

6.1、 范围生成器

cpp 复制代码
#include <boost/range/irange.hpp>
#include <boost/range/algorithm/copy.hpp>

// 生成整数范围 [0, 10)
auto range1 = boost::irange(0, 10);
// 包含: 0, 1, 2, ..., 9

// 指定步长 [0, 20),步长为 3
auto range2 = boost::irange(0, 20, 3);
// 包含: 0, 3, 6, 9, 12, 15, 18

// 生成递减范围 [10, 0),步长为 -2
auto range3 = boost::irange(10, 0, -2);
// 包含: 10, 8, 6, 4, 2

6.2 、连接多个范围

cpp 复制代码
#include <boost/range/join.hpp>
#include <boost/range/algorithm/copy.hpp>

std::vector<int> vec1 = {1, 2, 3};
std::list<int> vec2 = {4, 5, 6};
std::array<int, 3> vec3 = {7, 8, 9};

// 连接不同类型的容器
auto combined = boost::join(boost::join(vec1, vec2), vec3);

std::cout << "连接结果: ";
boost::copy(combined, std::ostream_iterator<int>(std::cout, " "));
// 输出: 1 2 3 4 5 6 7 8 9

6.3 、判断范围属性

cpp 复制代码
#include <boost/range/algorithm.hpp>
#include <boost/range/size.hpp>
#include <boost/range/empty.hpp>
#include <boost/range/distance.hpp>

std::vector<int> vec = {1, 2, 3, 4, 5};

// 获取范围大小
std::size_t sz = boost::size(vec);      // 5
std::ptrdiff_t dist = boost::distance(vec); // 5

// 检查是否为空
bool is_empty = boost::empty(vec);      // false

// 检查是否已排序
bool is_sorted = boost::is_sorted(vec); // true(如果已排序)

// 查找极值
auto min_it = boost::min_element(vec);  // 指向 1
auto max_it = boost::max_element(vec);  // 指向 5

7、性能考虑与最佳实践

7.1、 惰性求值的优势

Range 适配器采用惰性求值,这意味着:

cpp 复制代码
// 示例:处理大量数据
std::vector<int> big_data(1000000);
std::iota(big_data.begin(), big_data.end(), 0);

// 传统方式(立即计算,内存占用高)
std::vector<int> temp;
std::copy_if(big_data.begin(), big_data.end(), 
             std::back_inserter(temp),
             [](int x) { return x % 2 == 0; });
std::transform(temp.begin(), temp.end(), temp.begin(),
               [](int x) { return x * 2; });

// Range 方式(惰性计算,内存友好)
auto result = big_data 
    | boost::adaptors::filtered([](int x) { return x % 2 == 0; })
    | boost::adaptors::transformed([](int x) { return x * 2; });

// 只有在实际使用时才计算
int sum = 0;
for (int x : result | boost::adaptors::sliced(0, 100)) {
    sum += x;  // 只计算前100个元素
}

7.2、 何时复制 vs 何时使用视图

cpp 复制代码
// 情况1:需要修改原数据 → 使用算法
std::vector<int> data = {3, 1, 4, 1, 5};
boost::sort(data);  // 直接修改原容器

// 情况2:只需要读取或临时处理 → 使用适配器(视图)
auto even_view = data | boost::adaptors::filtered([](int x) {
    return x % 2 == 0;
});  // 不复制数据

// 情况3:需要持久化结果 → 复制到新容器
std::vector<int> even_numbers;
boost::copy(even_view, std::back_inserter(even_numbers));

7.3 、与 C++20 Ranges 的兼容性

如果你正在使用 C++20 或更新版本,可以考虑迁移到标准库的 <ranges>

cpp 复制代码
// C++20 标准 Ranges(对比 boost::range)
#include <ranges>
#include <algorithm>

std::vector<int> vec = {1, 2, 3, 4, 5};

// boost::range 方式
auto boost_result = vec 
    | boost::adaptors::filtered([](int x) { return x % 2 == 0; })
    | boost::adaptors::transformed([](int x) { return x * x; });

// C++20 Ranges 方式
auto std_result = vec
    | std::views::filter([](int x) { return x % 2 == 0; })
    | std::views::transform([](int x) { return x * x; });

迁移建议:

  1. 新项目优先使用 C++20 <ranges>
  2. 现有使用 boost::range 的项目可逐步迁移
  3. boost::range 在 C++11/14/17 项目中仍是优秀选择

8、 实战示例:数据处理管道

让我们通过一个完整的例子展示 boost::range 在实际项目中的应用:

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/irange.hpp>

struct Person {
    std::string name;
    int age;
    double salary;
};

int main() {
    std::vector<Person> employees = {
        {"Alice", 25, 50000.0},
        {"Bob", 30, 60000.0},
        {"Charlie", 35, 75000.0},
        {"David", 28, 55000.0},
        {"Eve", 40, 80000.0}
    };
    
    // 任务:找出年龄在30-40岁之间,薪资超过60000的员工名字
    auto result = employees
        | boost::adaptors::filtered([](const Person& p) {
            return p.age >= 30 && p.age <= 40;
        })
        | boost::adaptors::filtered([](const Person& p) {
            return p.salary > 60000.0;
        })
        | boost::adaptors::transformed([](const Person& p) {
            return p.name;
        });
    
    std::cout << "符合条件的员工: ";
    boost::copy(result, std::ostream_iterator<std::string>(std::cout, ", "));
    // 输出: Charlie, Eve,
    
    // 额外:计算平均薪资
    auto salaries = employees | boost::adaptors::transformed(
        [](const Person& p) { return p.salary; }
    );
    
    double total = 0.0;
    for (double s : salaries) {
        total += s;
    }
    double average = total / boost::size(employees);
    std::cout << "\n平均薪资: " << average << std::endl;
    
    return 0;
}

9、总结

boost::range 为 C++ 开发者提供了以下核心价值:

9.1 、主要优势

  1. 代码简洁性 :消除冗余的 begin()/end() 调用
  2. 安全性提升:减少迭代器不匹配的错误
  3. 表现力增强:支持流畅的函数式编程风格
  4. 性能优化:惰性求值减少不必要的计算和内存分配
  5. 兼容性好:支持 C++11 及以后版本,与 STL 无缝集成

9.2、 适用场景

  • 数据处理管道和转换
  • 算法链式调用
  • 大型数据集的惰性处理
  • 需要代码简洁性的项目
  • 准备向 C++20 Ranges 迁移的代码库

二、代码示例

1、示例代码

cpp 复制代码
#include <iostream>
#include <vector>
#include <tuple>

#include <boost/range.hpp>
#include <boost/range/irange.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/numeric.hpp>

// 简写命名空间,代码更清爽
namespace br = boost::range;
namespace ba = boost::adaptors;

// 打印工具
template<typename Range>
void print(const std::string& label, const Range& r)
{
    std::cout << label << ": ";
    for (auto v : r)
        std::cout << v << " ";
    std::cout << "\n";
}

int main()
{
    std::vector<int> data = { 1,2,3,4,5,6,7,8,9,10 };

    // 1. 生成数值区间
    auto nums = boost::irange(1, 11);
    print("irange 1~10", nums);

    // 2. 反转
    auto rev = data | ba::reversed;
    print("反转", rev);

    // 3. 过滤:只保留偶数
    auto even = data | ba::filtered([](int x) { return x % 2 == 0; });
    print("只保留偶数", even);

    // 4. 转换:全部平方
    auto square = data | ba::transformed([](int x) { return x * x; });
    print("全部平方", square);

    // 5. 链式组合:过滤偶数 + 平方 + 反转
    auto pipe = data
        | ba::filtered([](int x) { return x % 2 == 0; })
        | ba::transformed([](int x) { return x * x; })
        | ba::reversed;
    print("链式流水线", pipe);

    // 6. 切片 [2,6)
    auto slice = data | ba::sliced(2, 6);
    print("切片2~6", slice);

    // 7. 带下标遍历
    std::cout << "带下标遍历: ";
    for (auto item : data | ba::indexed(0))
    {
        std::cout << "(" << item.index() << "," << item.value() << ") ";
    }
    std::cout << "\n";

    // 8. range求和
    int sum = std::accumulate(boost::begin(data), boost::end(data), 0);
    std::cout << "数组总和 = " << sum << "\n";

    // 9.判断是否包含元素(不用contains)
    auto find_it = boost::find(data, 5);
    bool exist = (find_it != boost::end(data));
    std::cout << "是否包含5: " << std::boolalpha << exist << "\n";

    //10. range转vector(boost::begin/end)
    auto filter_view = data | ba::filtered([](int x) { return x > 5; });
    std::vector<int> res(boost::begin(filter_view), boost::end(filter_view));
    print("视图转vector", res);
    return 0;
}

2、运行结果

cpp 复制代码
irange 1~10: 1 2 3 4 5 6 7 8 9 10
反转: 10 9 8 7 6 5 4 3 2 1
只保留偶数: 2 4 6 8 10
全部平方: 1 4 9 16 25 36 49 64 81 100
链式流水线: 100 64 36 16 4
切片2~6: 3 4 5 6
带下标遍历: (0,1) (1,2) (2,3) (3,4) (4,5) (5,6) (6,7) (7,8) (8,9) (9,10)
数组总和 = 55
是否包含5: true
视图转vector: 6 7 8 9 10

D:\user\01417804\桌面\新建文件夹\Project1\x64\Debug\Project1.exe (进程 24260)已退出,代码为 0 (0x0)。
要在调试停止时自动关闭控制台,请启用"工具"->"选项"->"调试"->"调试停止时自动关闭控制台"。
按任意键关闭此窗口. . .
相关推荐
ch.ju6 小时前
Java Programming Chapter 4——lambda expression
java·开发语言
王燕龙(大卫)6 小时前
fastdds笔记
网络·c++·笔记
罗超驿6 小时前
10.Java对象比较完全指南:从equals到Comparable与Comparator
java·开发语言
脱胎换骨-军哥6 小时前
C++ 与 Go 生成质量比拼,谁是分布式主力语言
c++·分布式·golang
快乐星空Maker6 小时前
C++【生存游戏】开发:荒岛往事 第三期
开发语言·c++·游戏·编程语言
郝学胜-神的一滴6 小时前
Qt 高级编程 035:无边框窗口阴影以及圆角双特效实现
开发语言·c++·qt·程序人生·用户界面
正在走向自律6 小时前
实战心得:利用PaddleOCR彻底解决大模型无法解析图片型PDF的问题
开发语言·pdf·视觉检测·paddleocr·视觉模型·离线ocr识别
AA陈超6 小时前
006 T03 — 蓝图操作指南
c++·游戏·架构·ue5·github·虚幻引擎
小保CPP6 小时前
OCR C++ Tesseract从OpenCV中获取图片
c++·人工智能·opencv·ocr·模式识别·光学字符识别