具有Sentinels 和计数的ranges定义
ranges可能不仅是容器或一对迭代器
ranges可以通过以下方式定义:
- 相同类型的开始迭代器和结束迭代器
- 开始迭代器和
Sentinels(可能不同类型的结束标记) - 开始迭代器和计数
- 数组
range支持所有这些ranges的定义和使用。
首先,算法的实现方式是ranges可以是数组。例如:
int rawArray[] ={8,6,42,1,77};
...
std::ranges::sort(rawArray);
//对原始数组中的元素进行排序
此外,还有几个实用程序可以定义由迭代器和Sentinels 或计数定义的ranges
subrange 子ranges
为了定义迭代器和Sentinels 的ranges,ranges库提供了类型 std::ranges::subrange<>。让我们看一个使用子ranges的简单示例:
#include <iostream>
#include <compare>
#include <algorithm> //for for_each()
struct NullTerm{
bool operator== (auto pos) const {
return *pos == '\0'; //end 是迭代器指向 '0 的位置'
}
};
int main()
{
const char* rawString = "hello world"; // 定义原始字符串和 NULL 终止符的`ranges`:
std::ranges::subrange rawStringRange{rawString,Nu1lTerm{}}; //在算法中使用ranges
std::ranges::for_each(rawStringRange,
[](char c){
std::cout <<'·<<c; });
std::cout <<'\n';
// `ranges`总线 for 循环还支持迭代器/`Sentinels `:
for (char c : rawStringRange){
std::cout <<<<c;
}
std::cout <<'\n';
}
作为Sentinels 示例介绍的那样,我们将类型Nu11Term定义为Sentinels 的类型检查字符串的空终止符作为ranges的末尾。
通过使用 std::ranges::subrange,程序定义了一个表示字符串开头和Sentinels 作为其结尾的ranges对象:
std::ranges::subrange rawStringRange{rawString,NullTerm{}};
子ranges是泛型类型,可用于将迭代器和Sentinels 转换为将其表示为ranges的单个对象。事实上,ranges甚至是一个视图,它在内部只存储迭代器和Sentinels 。这意味着子ranges具有引用语义,并且复制它们的成本很低。
现在,我们可以将ranges传递给以ranges作为参数的新算法:
std::ranges::for_each(rawStringRange,
...);
请注意,子ranges的begin()和 end() 可能会产生不同的类型,因为它们只产生为定义ranges而传递的内容。
最后,请注意,基于 ranige 的 for 循环接受开始迭代器和结束迭代器类型不同的传递ranges(此功能已在 C++17 中引入,但对于ranges,您可以真正从中受益):
for (char c:std::ranges::subrange{rawString,NullTerm{}}){
std::cout <<''<<c;
}
我们可以通过定义一个类模板来使这种方法更加通用,您可以在其中指定结束ranges的值。请考虑以下示例:
#include <iostream>
#include <algorithm>
template<auto End>
struct EndValue {
bool operator==(auto pos) const {
return *pos ==End; //end 是迭代器指向 End 的位置
}
};
int main()
{
std::vector col1 = {42, 8, 0, 15, 7,-1};
// 定义一个`ranges` COLL 的开头和元素 7 作为结束:
std::ranges::subrange range{coll.begin(),EndValue<7>{}};
// 对此`ranges`的元素进行排序:
std::ranges::sort(range);
// 打印`ranges`的元素:
std::ranges::for_each(range,
[](auto val){
std::cout <<'<<val;
});
std::cout <<'\n';
// 打印 coll 的 ull 元素,最大为 -1:
std::ranges::for_each(coll.begin(),EndValue<-1>{},
[](auto val) {
std::cout<<'<<val;
});
std::cout <<'\n';
}
在这里,我们将 EndValue<> 定义为结束迭代器,检查作为模板参数传递的结束。EndValue<7>{} 创建一个结束迭代器,其中 7 结束ranges,EndValue<-1>{} 创建一个结束它 - erator,其中 1 结束ranges。
程序的输出如下所示
0 8 15 42
0 8 15 42 7
可以定义任何受支持的非类型模板参数类型的值。
作为Sentinels 的另一个例子,看看std::unreachable_sentinel。这是 C++20 定义的值,用于表示无限ranges的“结束”。它可以帮助优化代码,使其永远不会与结尾进行比较(因为当它总是产生 false 时,这种比较是无用的)。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情”