c++ view (视图)
为了处理ranges,c++ 20还引入了视图。
视图是轻量级ranges
-
可以参考
ranges和subranges -
可以通过过滤掉某些元素或对其值进行一些转换来迭代
ranges的元素 -
本身可以表示一系列值
例如,您可以使用一个视图只遍历一个ranges的前5个元素
or (const auto& elem : std::views::take(col1,5)) {
...
}
在这里,我们使用rangesaduptor std::views::take()。ranges适配器是在命名空间 std::views 中定义的帮助程序函数,用于创建视图。take() 创建传递ranges(如果有)的前 n 个元素的视图。
所以用
std::views::take(co11,5)
我们将一个视图传递给 coll,该视图以第六个元素(如果元素较少,则以最后一个元素)结尾。该视图提供了通常的ranges API,以便 begin()、end() 和运算符 ++ 可用于迭代元素,运算符 * 和 -> 可用于处理值。
std: :ranges: :sort(std::views::take(col1,5)); //对co11的前5个元素排序
视图本身还可以生成一系列值。例如,使用 iota 视图,我们可以迭代从 1 到 10 的所有值,如下所示:
for (int val : std::views::iota(1,11)) {
...
}
在内部,适配器使用视图类型,如 std::ranges::take_view 或 std::ranges::iota_view,您也可以直接使用这些视图类型。H无论如何,适配器应该是首选,因为它们通常更智能并启用优化。例如,如果传递的集合已经是string_view,则 take() 可能会生成string_view而不是take_view。
组合ranges和视图
未生成值的视图 1 可用作构建基块。
假设,您要使用以下三个视图:
// 用co11中3的倍数的元素来查看
std::views::filter(col1,[](auto elem){
return elem% 3== 0;
})
// 使用 coll 的平方元素查看:
std: :views: :transform(col1,[] (auto elem) {
return elem* elem;
})
//使用 coll 的前 3 个元素查看:
std::views::take(co11,3)
由于视图是一个ranges,因此可以将一个视图用作另一个视图的参数:
// 使用 coll 中元素的前 3 个平方值(3 的倍数)进行查看:
auto v = std::views::take(
std::views::transform(
std::views::filter(coll,
[](auto elem) { return elem % 3 == 0; }),
[] (auto elem) { return elem * elem; }),
3);
此嵌套难以读取和维护。但是,还有另一种组合ranges和视图的方法:视图允许使用运算符 I 在应处理的基础区域中管道:
// 视图 CO11 thut 中元素的前 3 个平方值是 3 的倍数:
auto v=co11
| std::views::filter([] (auto elem) { return elem% 3== 0;})
| std::views::transform([] (auto elem) { return elem * elem; })
| std::views::take(3);
此ranges和视图管道易于定义和理解。
对于诸如 std::vector coll{1, 2, 3, 4, 5, 6,7,8,9,10, 11,12,13};
输出将是:
9 36 81
下面是另一个完整的程序,它演示了使用管道语法的视图的可组合性:
#include <iostream>
#include <vector>
#include <map>
#include <ranges>
int main()
{
namespace vws = std::views;
std::vector<int> vals{ 0,1,2,3,4};
// 作曲家姓名及其出生年份地图:
std::map<std::string,int> composers{
{"Bach",1685},
{"Mozart",1756},
{"Beethoven",1770},
{"Tchaikovsky",1840},
{"Chopin",1810},
{"Vivaldi ",1678},
};
// 回顾自1700年以来出生的前3位作曲家的名字:
for (const auto& elem : composers
|vws::filter([](const auto& y) {
return y.second >=1700;
})
|vws::take(3)
|vws::keys
){
std::cout <<"- "<< elem <<'\n';
}
}
在这个例子中,我们将几个视图应用于作曲家的地图,其中元素有他们的名称和出生年份(请注意,我们引入了 vws 作为 std 的快捷方式::views):
std::map<std::string,int> composers{ ...};
...
composers
| vws::filter(...)
| vws::take(3)
| vws::keys
组合管道直接传递到基于ranges的 for 循环并生成以下输出(请记住,元素根据其键/名称进行排序):
-
Beethoven
-
Chopin
-
Mozart
不要使用 using 声明来跳过甚至编写 vws:::
using namespace std::views;
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情”