2012-07-11 6 views
9

Rozważmy następującą sekwencję:Jak napisać opakowanie iteratora, które łączy w sobie grupy wartości sekwencyjnych z podstawowego iteratora?

1, 2, 3, 4, 5, 6, 7, 8, 9, 10 

mam wejściowych iteratory dla tej sekwencji. Chcę owinąć te iteratorów na iteratory które produkują następującą sekwencję zamiast:

(1,2), (3,4), (5,6), (7,8), (9,10) 

Jeśli to nie jest jasne, to sekwencja to sekwencja kolejnych par kolejnych elementów z pierwotnego. Podczas gdy oryginał ma 10 elementów, ten ma 5: każdy jest otrzymywany z dwóch z oryginalnej sekwencji.

Używam doładowania na iterator_facade zaimplementować to, i mam ten zły próbę to:

template <typename Iterator> 
    struct pairing_iterator 
    : boost::iterator_facade< 
     pairing_iterator<Iterator>, 
     std::array<typename std::iterator_traits<Iterator>::value_type, 2>, 
     std::input_iterator_category 
     // I should probably customize reference too, but it's not relevant 
    > { 
     pairing_iterator(Iterator it) : it(it) { 
      increment(); // A 
     } 
     pairing_iterator::value_type dereference() const { 
      return pair; 
     } 
     bool equal(pairing_iterator const& that) const { 
      return it == that.it; // B 
     } 
     void increment() { 
      pair = { { *it++, *it++ } }; 
     } 
     Iterator it; 
     pairing_iterator::value_type pair; 
    }; 

Jeden problem mam skierowane jest na linii oznaczonej A: gdy iterator jest przekazywana w iterator końcowy, spowoduje to inkrementację, której nie mogę zrobić.

Kolejny znajduje się na linii oznaczonej literą B: Zachowuję pierwszy iterator zawsze przed "bieżącą" parą, więc jeśli iterator jest na ostatniej parze, to iterator będzie końcowym iteratorem, a tym samym porównać true z końcowym parametrem pairing_iterator.

Jeśli podstawowym iteratorem był forward iterator, mógłbym po prostu odczytać tę parę za każdym razem, gdy dokonano dereferencji, i po prostu dwa razy zwiększyć wartość kroku. Ale z Iteratory wejściowe mogę odczytać tylko raz.

Czy wymyślam nowe koło, które już istnieje? Nie znalazłem czegoś takiego w Boost, co mnie trochę zaskakuje. Ale chciałbym znaleźć gotowe rozwiązanie.

Jeśli to koło już nie ma, jak mogę je zmusić do rzucenia?

+0

Moim zdaniem jest to podobne do iteratora filtrowania. Twierdzę, że najlepiej jest, aby iterator zawierał iterator końcowy, aby obsłużyć przypadek, w którym sekwencja niespodziewanie zawiera nieparzystą liczbę elementów. To również rozwiązałoby oba problemy (A i B), ponieważ wiesz, czy jest to iterator końca, i możesz oddzielić realizację pary proxy od inkrementacji podstawowego iteratora. (Nie jestem zaznajomiony z fasadą iteratora Boosta, więc nie jestem do końca pewien, jak można to przetłumaczyć na Boosteese). –

+0

'Integer dereference()'? –

+0

@ David Oops, to był artefakt ode mnie "zakupy zbędnych szczegółów z dala od przykładu :) –

Odpowiedz

1

mam dwie propozycje już zestrzelonych na czacie, jeden z dziwne ale stosunkowo bezpieczny ograniczeń, a jeden z brzydkiego obejście ograniczeń:

Pierwszy pomysł jest bardzo prosty, ale wymaga dokładnie jednej dereference przed każda zaliczka

template <typename Iterator> 
struct pairing_iterator 
: boost::iterator_facade< 
    pairing_iterator<Iterator>, 
    std::array<typename std::iterator_traits<Iterator>::value_type, 2>, 
    std::input_iterator_category 
    // I should probably customize reference too, but it's not relevant 
> { 
    pairing_iterator(Iterator it) : it(it) { 
    } 
    pairing_iterator::value_type dereference() const { 
     auto t = *it++; 
     return { { std::move(t), *it } }; 
    } 
    bool equal(pairing_iterator const& that) const { 
     return it == that.it; 
    } 
    void increment() { 
     ++it; 
    } 
    Iterator it; 
}; 

Drugi pomysł usuwa jedno ograniczenie dokładnie wyłuskiwania, ale jest brzydkie i dziwne:

template <typename Iterator> 
struct pairing_iterator 
: boost::iterator_facade< 
    pairing_iterator<Iterator>, 
    std::array<typename std::iterator_traits<Iterator>::value_type, 2>, 
    std::input_iterator_category 
    // I should probably customize reference too, but it's not relevant 
> { 
    pairing_iterator(Iterator it) : it(it), dereferenced(false) { 
    } 
    pairing_iterator::value_type dereference() const { 
     if (!dereferenced) { 
      auto t = *it++; 
      pair = { { std::move(t), *it } }; 
      dereferenced = true; 
     } 
     return pair; 
    } 
    bool equal(pairing_iterator const& that) const { 
     return it == that.it; 
    } 
    void increment() { 
     if (!dereferenced) 
      dereference(); 
     dereferenced = false; 
     ++it; 
    } 
    Iterator it; 
    pairing_iterator::value_type pair; 
    bool dereferenced; 
}; 

i prawdopodobień Zrobiłem kilka błędów, ale mam nadzieję, że to wystarczy, aby przedstawić koncepcje.

+0

{{* it ++, * it}}; zwróci ten sam element dla każdego pola (lub jest niezdefiniowany), ponieważ ++ nie występuje, dopóki ';' ... – bytemaster

+0

@bytemaster: Nie jestem pewien, czy masz rację, ale na wszelki wypadek, naprawiłem to. To drobna zmiana. –

+0

@bytemaster nie, kolejność oceny w obrębie '{}' jest dobrze zdefiniowana. –

-1
template<typename T> 
struct piterator { 
    typedef std::pair<typename std::iterator_traits<T>::value_type, 
        typename std::iterator_traits<T>::value_type> value_type; 

    piterator(){} 
    piterator(const T& t, const T& e):itr(t),eitr(e){ 
    if(itr != eitr) head.first = *itr; 
    if(itr != eitr)head.second = *(++itr); 
    } 
    bool operator ==(const piterator& e)const { 
     return e.itr == itr && e.eitr== eitr; 
    } 

    value_type& operator*(){ return head; } 
    const value_type& operator*()const { return head; } 
    value_type& operator->(){ return head; } 
    const value_type& operator->()const { return head; } 

    piterator& operator++() { 
     if(itr != eitr)head.first = *(++itr); 
     if(itr != eitr)head.second = *(++itr); 
     return *this; 
    } 
    piterator& operator++(int) { 
     if(itr != eitr)head.first = *(++itr); 
     if(itr != eitr)head.second = *(++itr); 
     return *this; 
    } 
    private: 
    T itr; 
    T eitr; 
    value_type head; 
}; 

Konieczne będą dodatkowe kontrole, aby upewnić się, że iterator parowania nie "przekroczył końca" listy o nieparzystej wielkości.

+0

Jak wygląda * koniec * 'piterator'? AFAICT, będzie miał po prostu niezdefiniowane zachowanie prosto od konstruktora. –