用于生成视图的 std::ranges::iota_view 模板

743 阅读1分钟

生成视图

std::ranges::iota_view

类模板std::ranges::iota view<>是一个生成值序列的视图。这些值可以是整数,例如

  • 1,2,3...

  • 'a','b','c'...

或者可以使用运算符 ++ 来生成一系列指针或迭代器。

序列可能是有限的,也可能是无限的。

iota视图的主要用例是迭代值序列。

例如:

std::ranges::iota_view v1{1, 100};

	for (auto val : v1) {

		std::cout<<val<<'\n';  //打印这些值
		
		}

对于类模板,还提供了范围适配器 std::views::iota(),它接受一个或两个参数,因此您也可以编写:

for (auto val : std::views::iota(1, 100)) { //迭代值 1,2,...99

	std::cout <<val <<'\n'; //打印这些值 }

因为迭代器保存当前值,iota视图是一个借来的范围(它的迭代器的生命周期不依赖于视图)。如果iota视图受到限制,并且结束值与开始值具有相同的类型,则该视图为公共范围。

声明 iota 视图时,如下所示:

std::ranges::iota_view v1{1,100};

//值范围: 1,2,... 99

v1的类型被推导为std::ranges::iota view<int, int>,它创建了一个对象,该对象提供了基本API begin()和end(),生成这些值的迭代器。迭代器内部存储当前值,并在迭代器被递增时增加当前值

std::ranges::iota_view v1{1, 100};

//值范围: 1,2,... 99

auto pos = v1.begin();

//用值1初始化迭代器

std::cout <<*pos;

//打印当前值(这里是值1)

++pos;

//递增到下一个值(即,递增值到2)

std::cout <<*pos;

//打印当前值(这里是2)

因此,值的类型必须支持操作符++ 因此,像boolstd::string这样的值类型是不可能的。

注意,这个迭代器的类型取决于iota视图的实现,所以在这里使用它时必须使用auto。或者,你也可以用std::ranges::iterator t<v1>声明pos。

对于迭代器的range, value的范围是一个半开的范围,不包括结束值。

要包含结束值,可能必须增加结束值

std::ranges::iota_view letters{'a', 'z'+1}; //值: 'a', 'b',...'z'

	for (auto c :letters) {

		std::cout <<c<<'';

//打印这些值/字母

}

注意,这个循环的输出取决于字符集。只有当小写字母有连续的值时(就像ASCII或ISO-Latin-1或UTF-8的情况一样),视图只迭代小写字符。通过使用char8 t,您可以确保这是可移植的UTF-8字符的情况

std::ranges::iota_view letters{u8'a', u8'z'+1}; //UTF-8从a到z的值

如果没有传递结束值,则视图是无限的,并生成无限的值序列

std::ranges::iota_view v2{10L};

//无限范围,值:10L,11L,12L,…

std::ranges::iota_view<int> v3;

//无限范围,值:0,1,2,…

v3的类型是std::ranges::iota view<int,std::unreachable sentinel t,因此end()产生std::unreachable sentinel

无限iota视图是无穷无尽的。当迭代器表示最大值并迭代到下一个值时,它调用运算符++,这通常会执行溢出,以便下一个值是值类型的最小值。如果视图有一个永远不匹配的结束值,它的行为是一样的。

当用迭代器初始化iota视图时,iota视图遍历指向底层值的迭代器。在这种情况下,成员函数size()和操作符[]的可用性取决于传递范围内对这些操作符的支持程度。您可以使用它来处理指向范围所有元素的迭代器。

std::list<int> coll{2,4,6,8,10,12,14}; 

//将每个元素的迭代器传递给foo()

for (const auto& pos : std::views::iota(coll.begin(), coll.end())) {

	foo(pos);

}

您还可以使用它来初始化一个引用coll的所有当前元素的容器

std::ranges::iota_view itors{coll.begin(), coll.end()};

std::vector<std::ranges::iterator_t<decltype(col1)>> refColl{itors.begin(),

																itors.end()};

注意,如果您跳过指定refCo1l的元素类型,则必须使用圆括号。否则,将使用两个迭代器元素初始化vector

std::vector refCol1(collItors.begin(), collItors.end());

iota view<>的最后一个构造函数提供了用于支持可以创建iota视图的子视图的通用代码,例如drop视图

//从视图中删除第一个元素的泛型函数:

auto dropFirst = [] (auto v) {

	return decltype(v){++v.begin(),v.end()}; 
	
};

std::ranges::iota_view v1{1, 9};

auto v2 = dropFirst(v1); //从 2 到 9 的 iota 视图


开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情