c++ - 将迭代器作为 3 个元素的滑动窗口,可以越过边界(可能使用 Boost)

标签 c++ boost c++17

阅读 this SO post 并探索 Boost.Iterator 后,我想看看是否可以让大小为 3 的滑动窗口迭代通过单个 vector ,其中最终迭代具有“空的第三个元素”。

假设 vector 大小>=2,举个例子:

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

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

    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 迭代器实现,但我不知道它是否允许我超过结尾并得到一些空值。

我想过做一些 hacky 的事情,比如有一个虚拟的 final 元素,但后来我必须记录它,我试图用零 hacky 技巧编写干净的代码。

我也打算推出自己的迭代器,但显然是 std::iterator is deprecated

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

最佳答案

如果这只是在一个范围内设置一个大小的窗口,那么您真正想要的是一个可以推进的范围。在您的情况下,该范围有 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);}

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

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;
}

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

关于c++ - 将迭代器作为 3 个元素的滑动窗口,可以越过边界(可能使用 Boost),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51913520/

相关文章:

c++ - 尝试使用两个不同的数组来提问和回答问题

c++ - 在字符串中输入换行符

c++ - 将 boost::iostream::stream<boost::iostreams::source> 转换为 std::istream

c++ - 将 boost::shared_array<void> 转换为 boost::shared_array<int>

c++ - 使用 Boost.Log 和 Boost.ASIO 导致崩溃

c++ - 参数包和移动语义

c++ - Android 中的 C/C++?

c++ - 为什么 std::function::argument_type 已被弃用?

c++ - g++ c++17 类模板参数推导在非常特殊的情况下不起作用

c++ - 编写一个 C/C++ 程序来查找机器是 32 位还是 64 位