创建一个简单的前向迭代器,该迭代器在循环缓冲区的"end"处自动换行



我已经创建了一个简单的循环缓冲区,通过继承std::vector并重载其运算符[]来用向量大小对所需索引取模:

template <typename T>
class circvector : public std::vector<T> {
public:
T& operator[](size_t index) { return *(this->data() + index%this->size()); };       // modulo index by vector size when accessing with [] operator
};
int main()
{
circvector<int> buffer;                         // create a circvector
buffer.resize(10);                              // resize it
std::iota(buffer.begin(), buffer.end(), 0);     // fill with monotonically increasing integers
for (int i = 0; i < buffer.size() * 2; i++)
std::cout << buffer[i] << " ";              // access elements with [] beyond the circvector size is safe
}

它正确地产生输出:

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9

我还想创建一个"智能"前向输入迭代器,它支持运算符++(增量(和运算符*(解引用(以及,当它经过向量中的最后一个元素返回到与其关联的底层向量的开始时,它会自动"包装">

例如,这个假设的迭代器将允许在circvector的一个子集上更容易地执行算法库中的一些函数(通常将迭代器作为参数(,而无需添加逻辑来检查,然后当所需的子集跨越circvector-end->start-wrap时,将其拆分为两个单独的调用。

我一直在阅读关于创建自定义迭代器的文章,但描述中的信息似乎满足了我认为不需要的需求。再加上最近对std::迭代器的抨击,我甚至不知道从哪里开始创建我自己的迭代器,或者将它与我的circvector类相关联。

有人能让我开始使用一个最低限度的可操作模板吗?

这个类似乎实现了所需的行为,尽管它继承了不推荐使用的std::迭代器类:


template <typename T>
class circvector: public std::vector<T> {
public:
T& operator[](size_t index_) { return *(this->data() + index_%this->size()); };     // modulo index_ by vector size when accessing with [] operator
class iterator; // forward declaration
iterator begin() { return circvector<T>::iterator(*this, 0); }
iterator end() { return circvector<T>::iterator(*this, this->size()); } // will be same as begin() due to modulo in iterator constructor initializer list
private:
class iterator : public std::iterator<std::output_iterator_tag, T> {
private:
circvector<T>& container_;      // NOTE: ORDER MATTERS! // dependency injection
size_t index_{ 0 };         // NOTE: ORDER MATTERS! // state of iterator
public:
T& operator*() const { return container_[index_]; }                                     // this uses the overloaded operator[] which includes modulo
iterator& operator+(int N) { index_ = (index_ + N) % container_.size(); return *this; } // random increment by N
iterator& operator++() { index_ = (index_ + 1) % container_.size(); return *this; }     // increment with modulo
iterator operator++(int) { return ++(*this); }                                              // just calls prefix increment: operator++()
bool operator!=(const iterator & right) const { return index_ != right.index_ % container_.size(); }
bool operator==(const iterator & right) const { return index_ == right.index_ % container_.size(); }
explicit iterator(circvector<T>& container, size_t index_ = 0) : container_(container), index_(index_ % container_.size()) {}       // constructor
};
};

它是从https://lorenzotoso.wordpress.com/2016/01/13/defining-a-custom-iterator-in-c/

一个测试程序是:

int main()
{
circvector<int> buffer;
buffer.assign({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
auto start_offset{ 8 };
auto end_offset{ start_offset + 5 };
for (int i = 0; i < buffer.size(); i++) std::cout << buffer[i] << " ";
std::cout << "n";
std::for_each(buffer.begin() + start_offset, buffer.begin() + end_offset, [](auto& i) { i = 42; });
for (int i = 0; i < buffer.size(); i++) std::cout << buffer[i] << " ";
}

创建输出:

0 1 2 3 4 5 6 7 8 9
42 42 42 3 4 5 6 7 42 42

从begin((到end((的算法的使用当然不再有效,因为begin(((==end((。但是,只要长度比整个缓冲区大小小1,就可以使用算法(如图所示的std::for_each(对缓冲区的部分段进行操作。