假设我们有函数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;
});
这适用于我的编译器(标准库),但不符合随机访问迭代器,因为
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
。
所以我不明白如何使其符合,并且问题是否可能出现。
答案 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>
不是容器”,但我更倾向于认为引用的要求过于严格,而不是完全同意观点。