Membuat Iterators saya sendiri

141

Saya mencoba untuk belajar C ++ jadi maafkan saya jika pertanyaan ini menunjukkan kurangnya pengetahuan dasar, Anda lihat, faktanya adalah, saya memiliki kurangnya pengetahuan dasar.

Saya ingin bantuan untuk mengetahui cara membuat iterator untuk kelas yang saya buat.

Saya memiliki kelas 'Bentuk' yang memiliki wadah Poin. Saya memiliki kelas 'Potongan' yang mereferensikan suatu Bentuk dan mendefinisikan posisi untuk Bentuk tersebut. Sepotong tidak memiliki Bentuk itu hanya referensi Bentuk.

Saya ingin itu tampak seperti Piece adalah sebuah wadah Poin yang sama dengan orang-orang dari referensi Shape itu tetapi dengan offset posisi Piece ditambahkan.

Saya ingin bisa beralih melalui Poin Piece sama seperti jika Piece adalah wadah itu sendiri. Saya telah melakukan sedikit pembacaan dan belum menemukan apa pun yang telah membantu saya. Saya akan sangat berterima kasih atas petunjuk apa pun.

Howard May
sumber
6
Mem-posting kode sampel akan membantu menggambarkan apa yang Anda lakukan lebih baik daripada sekadar teks bahasa Inggris.
Greg Rogers
3
Membuat custom iterators mungkin bukan top top, setidaknya menengah.
ldog

Jawaban:

41

Anda harus menggunakan Boost.Iterators. Ini berisi sejumlah templat dan konsep untuk mengimplementasikan iterator dan adapter baru untuk iterator yang ada. Saya telah menulis artikel tentang topik ini ; itu di majalah ACCU Desember 2008. Ini membahas solusi elegan (IMO) untuk masalah Anda: mengekspos koleksi anggota dari suatu objek, menggunakan Boost.Iterators.

Jika Anda hanya ingin menggunakan stl, buku Josuttis memiliki bab tentang penerapan iterator STL Anda sendiri.

Roel
sumber
3
Hanya sedikit komentar: Buku ini berbicara tentang C ++ Standard Library, bukan STL - ini berbeda, tetapi banyak bingung (saya / saya juga bersalah)
CppChris
62

/ EDIT: Saya mengerti, iterator sendiri sebenarnya diperlukan di sini (saya salah membaca pertanyaannya). Tetap saja, saya membiarkan kode di bawah ini berdiri karena dapat bermanfaat dalam keadaan yang serupa.


Apakah iterator sendiri sebenarnya diperlukan di sini? Mungkin cukup untuk meneruskan semua definisi yang diperlukan ke wadah yang memegang Poin aktual:

// Your class `Piece`
class Piece {
private:
    Shape m_shape;

public:

    typedef std::vector<Point>::iterator iterator;
    typedef std::vector<Point>::const_iterator const_iterator;

    iterator begin() { return m_shape.container.begin(); }

    const_iterator begin() const { return m_shape.container.begin(); }

    iterator end() { return m_shape.container.end(); }

    const_iterator end() const { return m_shape.const_container.end(); }
}

Ini dengan asumsi Anda menggunakan vectorinternal tetapi jenisnya dapat dengan mudah disesuaikan.

Konrad Rudolph
sumber
mungkin dia ingin menggunakan algoritma STL atau fitur fungsional terhadap kelasnya ...
gbjbaanb
2
Pertanyaan asli sebenarnya mengatakan bahwa iterator wadah potongan harus mengubah nilai-nilai ketika mengembalikannya. Itu akan membutuhkan iterator yang terpisah, meskipun mungkin harus diwariskan atau diperoleh sebagian besar dari aslinya.
workmad3
@ gbjbaanb: Hal yang baik tentang kode saya adalah dapat digunakan oleh algoritma STL.
Konrad Rudolph
1
Beberapa tahun kemudian dan ini masih di antara hasil teratas di google ... Sekarang mungkin untuk menggeneralisasi ini dengan melakukan sesuatu seperti ini:auto begin() -> decltype(m_shape.container.begin()) { return m_shape.container.begin(); }
user2962533
20

Di sini Mendesain STL seperti Custom Container adalah artikel luar biasa yang menjelaskan beberapa konsep dasar tentang bagaimana kelas kontainer seperti STL dapat dirancang bersama dengan kelas iterator untuknya. Membalikkan iterator (sedikit lebih keras) meskipun dibiarkan sebagai latihan :-)

HTH,

Abhay
sumber
15

Anda dapat membaca artikel ddj ini

Pada dasarnya, mewarisi dari std :: iterator untuk menyelesaikan sebagian besar pekerjaan untuk Anda.

gbjbaanb
sumber
2
Catatan yang std::iteratorditandai ditinggalkan dari C ++ 17.
Mandrake
2

Menulis custom iterators di C ++ bisa sangat verbose dan rumit untuk dipahami.

Karena saya tidak dapat menemukan cara minimal untuk menulis iterator khusus, saya menulis tajuk template ini yang mungkin bisa membantu. Sebagai contoh, untuk membuat Piecekelas iterable:

#include <iostream>
#include <vector>

#include "iterator_tpl.h"

struct Point {
  int x;
  int y;
  Point() {}
  Point(int x, int y) : x(x), y(y) {}
  Point operator+(Point other) const {
    other.x += x;
    other.y += y;
    return other;
  }
};

struct Shape {
  std::vector<Point> vec;
};

struct Piece {
  Shape& shape;
  Point offset;
  Piece(Shape& shape, int x, int y) : shape(shape), offset(x,y) {}

  struct it_state {
    int pos;
    inline void next(const Piece* ref) { ++pos; }
    inline void begin(const Piece* ref) { pos = 0; }
    inline void end(const Piece* ref) { pos = ref->shape.vec.size(); }
    inline Point get(Piece* ref) { return ref->offset + ref->shape.vec[pos]; }
    inline bool cmp(const it_state& s) const { return pos != s.pos; }
  };
  SETUP_ITERATORS(Piece, Point, it_state);
};

Maka Anda akan dapat menggunakannya sebagai Kontainer STL normal:

int main() {
  Shape shape;
  shape.vec.emplace_back(1,2);
  shape.vec.emplace_back(2,3);
  shape.vec.emplace_back(3,4);

  Piece piece(shape, 1, 1);

  for (Point p : piece) {
    std::cout << p.x << " " << p.y << std::endl;
    // Output:
    // 2 3
    // 3 4
    // 4 5
  }

  return 0;
}

Ini juga memungkinkan untuk menambahkan jenis iterator lain seperti const_iteratoratau reverse_const_iterator.

Saya harap ini membantu.

VinGarcia
sumber
1

Solusi untuk masalah Anda bukanlah menciptakan iterator Anda sendiri, tetapi menggunakan wadah dan iterator STL yang ada. Simpan titik-titik di setiap bentuk dalam wadah seperti vektor.

class Shape {
    private:
    vector <Point> points;

Apa yang Anda lakukan sejak saat itu tergantung pada desain Anda. Pendekatan terbaik adalah beralih melalui titik-titik dalam metode di dalam Shape.

for (vector <Point>::iterator i = points.begin(); i != points.end(); ++i)
    /* ... */

Jika Anda perlu mengakses poin di luar Shape (ini bisa menjadi tanda dari desain yang kurang) Anda dapat membuat dalam metode Shape yang akan mengembalikan fungsi akses iterator untuk poin (dalam kasus itu juga membuat typedef publik untuk wadah poin). Lihatlah jawaban oleh Konrad Rudolph untuk detail dari pendekatan ini.

Diomidis Spinellis
sumber
3
Dia masih perlu membuat iterator sendiri yang meneruskan permintaan ke Piece to the Shapes yang ada di Piece itu. Iterator khusus adalah alat yang hebat di sini, dan sangat elegan untuk digunakan.
Roel