C++的范围库(std::ranges)添加于C++20,范围库是一个对迭代器和泛型算法库的扩展,使得迭代器和算法可以通过组合变得更强大,并且减少错误。
[begin, end) 迭代器对,例如可以从容器隐式获得范围。所有接受迭代器对的算法现在都有接受范围的重载(例如 ranges::sort)

[start, size) 有长度的序列,例如 views::counted 的结果
[start, predicate) 条件终止序列,例如 views::take_while 的结果
[start..) 未知边界序列,例如 views::iota 的结果
摘取自👉cppreference.com

受约束算法

👉受约束算法
示例
下述的示例用 lambda 表达式递增 vector 所有的元素,然后用函数对象中重载的 operator() 计算它们的和。注意,要计算总和的话,建议使用专用的算法 std::accumulate 。
例子:

#include <algorithm>
#include <cassert>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
 
struct Sum {
    void operator()(int n) { sum += n; }
    int sum{0};
};
 
int main() {
    std::vector<int> nums{3, 4, 2, 8, 15, 267};
 
    auto print = [](const auto& n) { std::cout << ' ' << n; };
 
    namespace ranges = std::ranges;
    std::cout << "before:";
    ranges::for_each(std::as_const(nums), print);
    print('\n');
 
    ranges::for_each(nums, [](int& n){ ++n; });
 
    // 对每个数调用 Sum::operator()
    auto [i, s] = ranges::for_each(nums.begin(), nums.end(), Sum());
    assert(i == nums.end());
 
    std::cout << "after: ";
    ranges::for_each(nums.cbegin(), nums.cend(), print);
 
    std::cout << "\n" "sum: " << s.sum << '\n';
 
    using pair = std::pair<int, std::string>; 
    std::vector<pair> pairs{{1,"one"}, {2,"two"}, {3,"three"}};
 
    std::cout << "project the pair::first: ";
    ranges::for_each(pairs, print, [](const pair& p) { return p.first; });
 
    std::cout << "\n" "project the pair::second:";
    ranges::for_each(pairs, print, &pair::second);
    print('\n');
}

结果:

before: 3 4 2 8 15 267 
after:  4 5 3 9 16 268
sum: 305
project the pair::first:  1 2 3
project the pair::second: one two tree

示例
以下代码用 fill() 设置 int 的 vector 的所有元素为 -1 :

#include <algorithm>
#include <iostream>
#include <vector>

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

    namespace ranges = std::ranges;
    ranges::fill(v.begin(), v.end(), -1);

    for (auto elem : v) {
        std::cout << elem << " ";
    }
    std::cout << "\n";

    ranges::fill(v, 10);

    for (auto elem : v) {
        std::cout << elem << " ";
    }
    std::cout << "\n";
}

结果:

-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
10 10 10 10 10 10 10 10 10 10

迭代器库的扩展

范围访问
定义于头文件 <ranges>
定义于头文件 <iterator>

ranges::begin(C++20) 返回指向范围起始的迭代器 (定制点对象)
ranges::end(C++20) 返回指示范围结尾的哨位 (定制点对象)
ranges::cbegin(C++20) 返回指向只读范围起始的迭代器 (定制点对象)
ranges::cend(C++20) 返回指示只读范围结尾的哨位 (定制点对象)
ranges::rbegin(C++20) 返回指向范围的逆向迭代器 (定制点对象)
ranges::rend(C++20) 返回指向范围的逆向尾迭代器 (定制点对象)
ranges::crbegin(C++20) 返回指向只读范围的逆向迭代器 (定制点对象)
ranges::crend(C++20) 返回指向只读范围的逆向尾迭代器 (定制点对象)
ranges::size(C++20) 返回等于范围大小的整数 (定制点对象)
ranges::ssize(C++20) 返回等于范围大小的有符号整数 (定制点对象)
ranges::empty(C++20) 检查范围是否为空 (定制点对象)
ranges::data(C++20) 获得指向连续范围的起始的指针 (定制点对象)
ranges::cdata(C++20) 获得指向只读连续范围的起始的指针 (定制点对象)

例子:

#include <iostream>
#include <vector>
#include <ranges>
 
int main() {
    std::vector<int> v = { 3, 1, 4 };
    auto vi = std::ranges::begin(v);
    std::cout << *vi << '\n';
    *vi = 42; // OK
 
    int a[] = { -5, 10, 15 };
    auto ai = std::ranges::begin(a);
    std::cout << *ai << '\n';
    *ai = 42; // OK
}
3
-5
#include <cstring>
#include <iostream>
#include <ranges>
#include <string>
 
int main() {
    std::string s {"Hello world!\n"};
 
    char a[20]; // C 风格字符串的存储
    std::strcpy(a, std::ranges::data(s));
    // [data(s), data(s) + size(s)] 保证为 NTBS
 
    std::cout << a;
}

结果:

Hello world!
#include <ranges>
#include <iostream>
 
int main() {
    auto const ints = {0,1,2,3,4,5};
    auto even = [](int i) { return 0 == i % 2; };
    auto square = [](int i) { return i * i; };
 
    // 组合视图的“管道”语法:
    for (int i : ints | std::views::filter(even) | std::views::transform(square)) {
        std::cout << i << ' ';
    }
 
    std::cout << '\n';
 
    // 传统的“函数式”组合语法:
    for (int i : std::views::transform(std::views::filter(ints, even), square)) {
        std::cout << i << ' ';
    }
}

结果:

0 4 16
posted on 2022-12-13 13:55  txt1994  阅读(57)  评论(0编辑  收藏  举报
返回顶端