2021年6月10日 星期四

如何使用 forrange 疊代 class 的成員

如何使用 forrange 疊代 class 的成員

tags: 部落格文章


什麼是 forrange

這東西其實很好用,也很容易在別的代碼裡看到,他長這個樣子

vector<int> v{1, 2, 3};
for(auto&& i : v)
    cout << i << endl;

上面這個例子就會自己把結果疊代出來了,forrange這個東西展開來其實是用iterator實現的,差不多會等於下面的代碼

for (Vector<int>::iterator it = v.begin() ; it != v.end(); ++it)
    std::cout << *it << std::endl;

由這邊可以看出來我們需要實現的有這幾個大項

  1. Range::begin();
  2. Range::end();
  3. class iterator{};
  4. iterator::operator==()
  5. iterator::operator!=()
  6. iterator::operator*()



建立一個class

首先先讓我們把自己的class建造出來,大概就是簡單管理一個陣列即可。

class Range {
public:
    using _type = int;
public:
    Range(){}
    Range(initializer_list<_type> l): len(l.size()) {
        arr = new _type[l.size()];
        std::copy(l.begin(), l.end(), arr);
    }
    ~Range() {
        delete[] arr;
    }
private:
    _type* arr = nullptr;
    size_t len = 0;
};


iterrator 類別

差不多就這樣簡單即可,接下來要建造一個 iterrator 的類別(直接包在類別內就可以),還有完成剛剛提到那幾個函式。

在這個類別裡需要兩個成員資料,一個是我們自己建造的類別,一個是當前的指針跑到第幾個了。

struct Iterator {
    private:
        Range const* r;
        int current;
}

接下來是個別的函式

    struct Iterator {
    public:
        Iterator(Range const* x, size_t c) : r(x), current(c) {}
        Iterator& operator++() {
            ++current;
            return *this;
        }
        Iterator operator++(int) {
            Iterator old = *this;
            operator++();
            return old;
        }
        const _type& operator*() const{
            return r->arr[current];
        }
        friend bool operator==(Iterator const& x, Iterator const& y) {
            return x.current == y.current;
        }
        friend bool operator!=(Iterator const& x, Iterator const& y) {
            return !(x == y);
        }
    private:
        Range const* r;
        int current;
    };

建造好之後就可以使用摟


完整範例

#include <iostream>
#include <Iterator>
#include <initializer_list>
using namespace std;

class Range {
public:
    using _type = int;
public:
    Range(){}
    Range(initializer_list<_type> l): len(l.size()) {
        arr = new _type[l.size()];
        std::copy(l.begin(), l.end(), arr);
    }
    ~Range() {
        delete[] arr;
    }
private:
    _type* arr = nullptr;
    size_t len = 0;

public:
    struct Iterator {
    public:
        Iterator(Range const* x, size_t c) : r(x), current(c) {}
        Iterator& operator++() {
            ++current;
            return *this;
        }
        Iterator operator++(int) {
            Iterator old = *this;
            operator++();
            return old;
        }
        const _type& operator*() const{
            return r->arr[current];
        }
        friend bool operator==(Iterator const& x, Iterator const& y) {
            return x.current == y.current;
        }
        friend bool operator!=(Iterator const& x, Iterator const& y) {
            return !(x == y);
        }
    private:
        Range const* r;
        int current;
    };
    Iterator begin() const {
        return Iterator(this, 0);
    }
    Iterator end() const {
        return Iterator(this, len);
    }
};

int main() {
    Range r{1, 2, 3};
    for (auto&& i : r) {
        cout << i << ", ";
    } cout << endl;
}

參考

  1. https://cpprefjp.github.io/lang/cpp11/range_based_for.html
  2. https://stackoverflow.com/questions/46431762/how-to-implement-standard-iterators-in-class
  3. https://stackoverflow.com/questions/13407309/c-iterator-within-a-class/13407381
  4. https://www.cplusplus.com/reference/iterator/iterator/

沒有留言:

張貼留言