将迭代器作为 3 个元素的滑动窗口,可以超调边界(可能使用 Boost)

Having an iterator as a sliding window of 3 elements that can overshoot bounds (possibly using Boost)

本文关键字:边界 Boost 迭代器 元素 窗口      更新时间:2023-10-16

阅读了这篇文章并探索了 Boost.Iterator,我想看看我是否可以让大小为 3 的滑动窗口迭代单个向量,其中最终迭代具有"空的第三个元素"。

假设向量大小为>= 2,举个例子:

{a, b, c, d, e, f, g}

我们将始终从索引 1 开始,因为我正在实现的这个算法需要一个"上一个"元素存在,并且不需要对第一个元素进行操作(因此我们将在i < size()时从i = 1迭代(:

V
[a, b, c]
{a, b, c, d, e, f, g}

当我移动到下一个迭代时,它看起来像:

V
[b, c, d]
{a, b, c, d, e, f, g}

在到达迭代中的最后一个元素时,它将具有以下内容:

V
[f, g, EMPTY]
{a, b, c, d, e, f, g}

我想要的是能够抓取"prev"并检查"hasNext"并获取下一个元素(如果可用(。我的目标是非常干净的现代C++代码,并且它不对三个不同元素的跟踪指针/引用进行簿记,使代码更加干净:

for (const auto& it : zippedIterator(dataVector)) {
someFunc(it.first, triplet.second);
if (someCondition(it.second) && hasThirdElement) {
anotherFunc(it.second, it.third)
}
}

我试图看看 boost 的 zip 迭代器是否可以做到这一点,但我不知道它是否允许我超调末端并有一些空值。

我想过做一些黑客的事情,比如有一个虚拟的最终元素,但随后我必须记录它,我正在尝试用零黑客技巧编写干净的代码。

我也打算推出我自己的迭代器,但显然 std::itrator 已被弃用。

我也不想创建底层向量的副本,因为这将用于需要快速的紧密循环中,并且复制所有内容对于底层对象来说将非常昂贵。它不需要非常优化,但将迭代器值复制到新数组是不可能的。

如果这只是一个范围的大小窗口的问题,那么你真正想要的是一个可以前进的范围。在您的情况下,该范围有 3 个元素长,但没有理由通用机制不允许可变大小的范围。它只是一对迭代器,这样你可以++或 - 同时使用它们。

您遇到的问题是,如果子范围不在范围的末尾,则要制造元素。这使事情复杂化;这将需要代理迭代器等等。

如果您想要针对特定情况的解决方案(3 元素大小的范围,如果最后一个元素不在主范围的末尾,则可以制造最后一个元素(,那么您首先需要决定是否要为此提供实际类型。也就是说,是否值得实现一个完整的类型,而不是几个一次性的实用程序函数?

我处理这个问题的方法是重新定义问题。您似乎拥有的是当前元素,就像任何其他迭代一样。但是您希望能够访问上一个元素。并且您希望能够向前窥视下一个元素;如果没有,那么你想制造一些默认值。所以。。。执行迭代,但编写几个实用程序函数,以便从当前元素访问所需的内容。

for(auto curr = ++dataVector.begin();
curr != dataVector.end();
++curr)
{
someFunc(prevElement(curr), *curr);
auto nextIt = curr + 1;
if(nextIt != dataVector.end() && someCondition(*curr))
anotherFunc(*curr, *nextIt)
}

prevElement是一个简单的函数,它在给定迭代器之前访问元素。

template<typename It>
//requires BidirectionalIterator<It>
decltype(auto) prevElement(It curr) {return *(--curr);}

如果你想有一个函数来检查下一个元素并为它制造一个值,那也可以做到。这个必须返回元素的 prvalue,因为我们可能必须制造它:

template<typename It>
//requires ForwardIterator<It>
auto checkNextElement(It curr, It endIt)
{
++curr;
if(curr == endIt)
return std::iterator_traits<It>::value_type{};
return *curr;
}

是的,这并不全是聪明的,有特殊的范围类型等。但是你正在做的事情并不常见,尤其是你必须像你一样制造下一个元素。通过保持简单明了,您可以让某人轻松阅读您的代码,而无需了解某些专门的子范围类型。