c++20 ranges库

ranges库在对元素进行逐一操作或者判断时可以省掉很多循环体,使代码的可读性提高。

例如,要从一个vector中拿出所有的偶数并求平方并逆序排列,生成一个新的vector,以前这样写:

vector<int> v1 = {0, 1, 2, 3, 4};
vector<int> v2;
for (auto i : v1) {
    if (i % 2 == 0) {
        v2.push_back(i * i);
    }
}
vector<int> v3(v2.rbegin(), v2.rend());

有了ranges后就可以用管道符(|)的形式写,对数据先后做了怎样的操作一目了然。

for (int i : v1 | views::filter([](int i) { return i % 2 == 0; })
                | views::transform([](int i) { return i * i; })
                | views::reverse) {
    printf("%d ", i);
}

下面我们了解一下这个库

首先是range的概念,它是一个concepts,定义如下:

即任何类型,只要它有首尾迭代器,它就是个range。我们常用的STL、数组、string,都是range。

然后是view(视图)的概念,它是指一段元素从某个“视角”看过去的样子,在这个视图中的真实值都是惰性求值的,拿上面这个例子来说,看似我们对一段range进行了逐元素求平方的操作,实际上这个操作是在遍历过程中计算的,并不是在生成这个view对象时计算的。因此view只是一个壳子,它不具有元素真正的内存空间,可以进行任意拷贝。

下面介绍几种range adapter,它用来对一段range或view生成另一个view

1. filter view,对一段view进行过滤,筛选出符合条件的元素

vector<int> vec{0, 1, 2, 3, 4};  // 用vector作为一个range
auto even = [](int i) { return i % 2 == 0; };  // 过滤出其中的所有偶数
for (int i : vec | views::filter(even)) {  // 管道符形式
    printf("%d ", i);
}
for (int i : views::filter(vec, even)) {  // 函数形式
    printf("%d ", i);
}
for (int i : ranges::filter_view(vec, even)) {  // 函数形式
    printf("%d ", i);
}

auto v = vec | views::filter(even);
vector<int> b(v.begin(), v.end());  // 用view的迭代器来构造一个新的vector

2. transform view,对一段view进行逐元素的变换

string str{"Hello"};  // 用string作为一个range
auto to_upper = [](char c) { return toupper(c); };  // 将每个元素都转为大写
for (char c : str | views::transform(to_upper)) {  // 管道符形式
    printf("%c", c);
}
for (char c : views::transform(str, to_upper)) {  // 函数形式
    printf("%c", c);
}
for (char c : ranges::transform_view(str, to_upper)) {  // 函数形式
    printf("%c", c);
}

auto v = str | views::transform(to_upper);
string s(v.begin(), v.end());  // 用view的迭代器来构造一个新的string

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值