Kendi Yineleyicilerimi Oluşturma


141

C ++ öğrenmeye çalışıyorum, eğer bu soru temel bilgi eksikliğini gösteriyorsa beni affet, görüyorsun, aslında, temel bilgi eksikliğim var.

Oluşturduğum bir sınıf için yineleyici oluşturma konusunda biraz yardım istiyorum.

Puan kapsayıcı bir sınıf 'Şekil' var. Bir şekli referans ve şekil için bir konum tanımlayan bir parça 'parça' var. Parçanın şekli yoktur, sadece bir şekle gönderme yapar.

Parça, referans aldığı Şekil ile aynı olan Puan Parçası gibi görünmesini istiyorum, ancak Parça konumunun ofseti eklenmiştir.

Piece'in bir konteynerin kendisiymiş gibi Piece'in Puanlarını tekrar edebilmek istiyorum. Biraz okuma yaptım ve bana yardımcı olacak hiçbir şey bulamadım. İşaretçiler için çok minnettar olurum.


6
Örnek kod yayınlamak, ne yaptığınızı basit İngilizce metinden daha iyi tanımlamanıza yardımcı olacaktır.
Greg Rogers

3
Özel yineleyiciler oluşturmak, muhtemelen en azından temel bir üst düzey değildir .
Şubat'ta ldog

Yanıtlar:


41

Boost.Iterators kullanmalısınız. Mevcut yineleyiciler için yeni yineleyiciler ve bağdaştırıcılar uygulamak için bir dizi şablon ve kavram içerir. Bu konuyla ilgili bir makale yazdım ; Aralık 2008 ACCU dergisinde. Tam olarak sorununuz için (IMO) şık bir çözümü tartışır: Boost.Iterators kullanarak bir nesneden üye koleksiyonlarını göstermek.

Yalnızca stl kullanmak istiyorsanız, Josuttis kitabının kendi STL yineleyicilerinizin uygulanması hakkında bir bölümü vardır.


3
Sadece küçük bir açıklama: Kitap C ++ Standart Kütüphanesi hakkında konuşuyor, STL hakkında değil - bunlar farklı, ama çok karıştı (Ben de suçluyum / suçluydum)
CppChris

62

/ EDIT: Anlıyorum, burada kendi yineleyici gerekli (önce soruyu yanlış okudum). Yine de, benzer durumlarda yararlı olabileceğinden aşağıdaki kodun durmasına izin veriyorum.


Burada gerçekten kendi yineleyici gerekli mi? Belki de gerekli tüm tanımları gerçek Puanları içeren kaba iletmek yeterlidir:

// 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(); }
}

Bu, vectordahili olarak kullandığınızı varsayar, ancak tür kolayca uyarlanabilir.


belki de sınıfına karşı STL algoritması veya fonksiyonel özellikleri kullanmak istiyor ...
gbjbaanb

2
Orijinal soru aslında parça kabının yineleyicisinin değerleri döndürürken değiştirmesi gerektiğini söylüyor. Bu muhtemelen ayrı bir yineleyici gerektirir, ancak büyük olasılıkla orijinalden miras alınmalı veya başka şekilde elde edilmelidir.
workmad3

@gbjbaanb: my kodu hakkında iyi bir şey olduğunu olabilir STL algoritmaları tarafından kullanılacaktır.
Konrad Rudolph

1
Birkaç yıl sonra ve bu hala Google'da en iyi sonuçlar arasında ... Şimdi böyle bir şey yaparak bunu genellemek mümkün:auto begin() -> decltype(m_shape.container.begin()) { return m_shape.container.begin(); }
user2962533

20

Burada Özel Konteyner gibi bir STL tasarlamak , bir STL benzeri konteyner sınıfının bunun için yineleyici sınıfıyla birlikte nasıl tasarlanabileceğine dair bazı temel kavramları açıklayan mükemmel bir makaledir. Ters yineleyici (biraz daha sert) bir egzersiz olarak bırakılır :-)

HTH,



2

C ++ 'da özel yineleyiciler yazmak oldukça ayrıntılı ve anlaşılması karmaşık olabilir.

Özel bir yineleyici yazmak için minimal bir yol bulamadığım için yardımcı olabilecek bu şablon başlığını yazdım . Örneğin, Piecesınıfı tekrarlanabilir yapmak için :

#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);
};

Daha sonra normal bir STL Kabı olarak kullanabilirsiniz:

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

Ayrıca, const_iteratorveya gibi diğer yineleyicilerin eklenmesine de izin verir reverse_const_iterator.

Umut ediyorum bu yardım eder.


1

Sorununuzun çözümü kendi yineleyicilerinizin oluşturulması değil, mevcut STL kaplarının ve yineleyicilerin kullanılmasıdır. Her şekildeki noktaları vektör gibi bir kapta saklayın.

class Shape {
    private:
    vector <Point> points;

Bundan sonra ne yapacağınız tasarımınıza bağlıdır. En iyi yaklaşım, Şekil içindeki yöntemlerde noktaları tekrarlamaktır.

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

Şekil dışındaki noktalara erişmeniz gerekiyorsa (bu, eksik bir tasarımın işareti olabilir), noktalar için yineleyici erişim işlevlerini döndürecek Şekil yöntemlerinde oluşturabilirsiniz (bu durumda noktalar kabı için genel bir typedef de oluşturabilirsiniz). Bu yaklaşımın ayrıntıları için Konrad Rudolph'un cevabına bakınız.


3
Hâlâ Parçaya talepleri, o Parçadaki Şekillere ileten kendi yinelemesini yapması gerekecektir. Özel yineleyiciler burada harika bir araçtır ve kullanımı çok zariftir.
Roel
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.