是否可以编写标准的符合随机访问(或至少前向)整数迭代器?

时间:2016-07-30 15:13:24

标签: c++ iterator language-lawyer

假设我们有函数f,它接受​​整数并返回一个单调增加的值。我们希望找到最小x,以便f(x) >= C。为简单起见,我们说答案在[l;r)范围内。显然我们可以编写自己的二进制搜索实现,但我们想要使用现有的(std::patition_point)。

如此天真的实施(可能)有效:

// f;
std::vector<int> v(r - l);
std::iota(v.begin(), v.end(), l);
answer = l + partition_point(v.begin(), v.end(), [&](int x) {
    return f(x) <= C;
}) - v.begin();

显而易见的问题是,我们必须存储占用大量内存的所有数字,并且还需要时间来填充数组

下一个逻辑思路是以这种方式将整数包装到迭代器:

struct IntIterator: std::iterator<std::random_access_iterator_tag, int> {
    int current;
    IntIterator(int i) : current(i) {}
    int operator*() const { return current; }
    IntIterator& operator++() { ++current; return *this; }
    IntIterator& operator+=(size_t n) { current += (int)n; return *this; }
    IntIterator operator+(size_t n) const { return current+(int)n;  }
    size_t operator-(IntIterator that) const { return size_t(current - that.current); }
    // others operators to conform 
};

answer = partition_point(IntIterator{l}, IntIterator{r}, [&](int x) {
    return f(x) <= C;
});

这适用于我的编译器(标准库),但不符合随机访问迭代器,因为

  • operator *应返回std::iterator_traits<IntIterator>::reference
  • 如果我们将std::iterator_traits<IntIterator>::reference更改为int(例如,通过将模板参数更改为std::iterator),它将无法满足forward iterator的要求:

      

    如果X是可变迭代器,reference是对T的引用;如果X是常量迭代器,reference是对const T的引用,

  • 如果我们将operator*的返回类型更改为[const ]T&,它将无法满足前向迭代器的另一个要求

      

    如果a和b都是可解除引用的,那么当且仅当a == b*a绑定到同一个对象时才*b

所以我不明白如何使其符合,并且问题是否可能出现。

2 个答案:

答案 0 :(得分:3)

迭代器共享一个指向缓存映射的指针。

缓存映射将索引映射到(count,value),其中count是该索引处的迭代器数。

迭代器会记住它是否调用*

调用*时,如果缺少值,则填充该值。无论如何,count递增,然后返回对value的引用。

当迭代器被销毁或迭代器移动(++)时,如果调用了*,则递减计数。

如果count减少为零,则删除该条目。

这会在相同索引的集体重叠生命周期内缓存所有有效迭代器的值。

答案 1 :(得分:0)

  

如果X是可变迭代器,reference是对T的引用;如果X是常量迭代器,则reference是对const T的引用

我认为你不应该太认真地对待这个要求。标准库包含std::vector<bool>const_iterator无法满足此要求的容器(iterator)。我知道a point of view std::vector<bool>不是容器”,但我更倾向于认为引用的要求过于严格,而不是完全同意观点。