c++ 20 view (视图)

1,113 阅读3分钟

c++ view (视图)

为了处理ranges,c++ 20还引入了视图。

视图是轻量级ranges

  • 可以参考rangessubranges

  • 可以通过过滤掉某些元素或对其值进行一些转换来迭代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_viewstd::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 天,点击查看活动详情