簡體   English   中英

創建一個簡單的前向迭代器,它自動在循環緩沖區的“末端”換行

[英]Create a simple forward iterator which automatically wraps at the “end” of a circular buffer

我通過繼承 std::vector 並重載其 operator[] 創建了一個簡單的循環緩沖區,以將所需的索引與向量大小取模:

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
}

正確生成 output:

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

我還想創建一個“智能”前向輸入迭代器,它支持 operator++ (增量)和 operator* (取消引用),並且在經過向量中的最后一個元素回到底層向量的開頭自動“換行”它是相關的。

例如,這個假設的迭代器將允許在循環向量的子集上更輕松地執行算法庫中的某些函數(通常將迭代器作為參數),而無需添加邏輯來檢查,然后在所需的子集跨越時拆分為兩個單獨的調用圓向量的結束->開始環繞。

我一直在閱讀有關創建自定義迭代器的內容,但描述變得非常復雜,其中包含看似滿足我認為不需要的要求的信息。 再加上最近棄用 std::iterator 的討論,我什至不知道從哪里開始創建我自己的迭代器,或者將它與我的 circvector class 相關聯。

有人可以讓我開始使用一個最低限度可行的模板來運行嗎?

這個 class 似乎實現了所需的行為,盡管它繼承自已棄用的 std::iterator class:


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

創建 output:

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

從 begin() 到 end() 的算法的使用當然不再有效,因為 begin()==end()。 但是您可以使用算法(如所示的 std::for_each )對緩沖區的部分段進行操作,只要長度比完整緩沖區大小小 1 即可。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM