2011-09-26 10 views
57

Piszę Iterator dla kontenera, który jest używany zamiast pojemnika STL. Obecnie pojemnik STL jest używany w wielu miejscach z c++11 foreach syntax, np .: for(auto &x: C). Mamy potrzebne do aktualizacji kodu do korzystania z niestandardowej klasy, która otacza pojemnik STL:Składnia foreach i niestandardowa iterator C++ 11

template< typename Type> 
class SomeSortedContainer{ 
    std::vector<typename Type> m_data; //we wish to iterate over this 
    //container implementation code 
};  
class SomeSortedContainerIterator{ 
    //iterator code 
}; 

Jak mogę dostać auto używać poprawnej iterator dla niestandardowego pojemnika tak, że kod jest w stanie nazwać w następujący sposób ?:

SomeSortedContainer C; 
for(auto &x : C){ 
    //do something with x... 
} 

Ogólnie rzecz biorąc, co jest wymagane, aby automatycznie używać poprawnego iteratora dla klasy?

+0

Jeśli używasz programu Visual Studio, możesz najechać myszą na nazwę zmiennej, aby zobaczyć jej typ. IIRC, pokazuje rzeczywisty typ, a nie 'auto'. –

Odpowiedz

50

Masz dwie możliwości:

  • ty wykonywania funkcji członków nazwanych begin i end które mogą być wywoływane jak C.begin() i C.end();
  • inaczej, należy podać bezpłatne funkcje nazwane begin i end, które można znaleźć za pomocą odnośnika argumentów zależne, lub w przestrzeni nazw std, a można nazwać jak begin(C) i end(C).
+2

Zobacz Stroustrup [C++ 11 FAQ] (http://www.stroustrup.com/C++11FAQ.html), aby uzyskać szczegółowy opis instrukcji ["Range-for"] (http: //www.stroustrup .com/C++ 11FAQ.html # for) (w tym pierwszeństwo funkcji/funkcji). – rluba

50

Aby móc korzystać z zasięgu, klasa powinna zapewniać członkom const_iterator begin() const i const_iterator end() const. Możesz także przeciążyć globalną funkcję begin, ale mając funkcję członka jest lepiej moim zdaniem. iterator begin() i const_iterator cbegin() const są również zalecane, ale nie są wymagane. Jeśli chcesz po prostu iteracyjne nad pojedynczy pojemnik wewnętrzny, to jest bardzo proste:

template< typename Type> 
class SomeSortedContainer{ 

    std::vector<Type> m_data; //we wish to iterate over this 
    //container implementation code 
public: 
    typedef typename std::vector<Type>::iterator iterator; 
    typedef typename std::vector<Type>::const_iterator const_iterator; 

    iterator begin() {return m_data.begin();} 
    const_iterator begin() const {return m_data.begin();} 
    const_iterator cbegin() const {return m_data.cbegin();} 
    iterator end() {return m_data.end();} 
    const_iterator end() const {return m_data.end();} 
    const_iterator cend() const {return m_data.cend();} 
};  

Jeśli chcesz iteracyjne nad niczego zwyczaj chociaż, prawdopodobnie będziesz musiał zaprojektować własne iteratory jako klasy wewnątrz pojemnika.

class const_iterator : public std::iterator<random_access_iterator_tag, Type>{ 
    typename std::vector<Type>::iterator m_data; 
    const_iterator(typename std::vector<Type>::iterator data) :m_data(data) {} 
public: 
    const_iterator() :m_data() {} 
    const_iterator(const const_iterator& rhs) :m_data(rhs.m_data) {} 
    //const iterator implementation code 
}; 

Aby uzyskać więcej informacji na temat pisania klasy iteratora, zobacz my answer here.

2

Według mojej wiedzy SomeSortedContainer wystarczy podać begin() i end(). Powinny one zwrócić standardowy iterator zgodny z Twoimi danymi, w twoim przypadku SomeSortedContainerIterator, który faktycznie byłby opakowany pod std::vector<Type>::iterator. W przypadku standardowej zgodności mam na myśli zapewnienie operatorom zwykłych inkrementacji i dereferencji, ale także wszystkim tym typom, które z kolei są używane przez konstruktor foreach do określenia podstawowego rodzaju elementów kontenera. Ale możesz po prostu przekazać je od std::vector<Type>::iterator.

+3

Jeśli nie masz funkcji "begin" i "end", to foreach może również używać funkcji "begin" i "end" non-member. –

+0

@Mike Czy chodzi ci o bezpłatne funkcje przyjmujące kontener jako pojedynczy parametr? Miło, nie wiedziałem tego. Przydaje się to do rozszerzenia istniejących klas kontenerowych. –

6

Jak inni stwierdzili, twój pojemnik musi wdrożyć begin() i end() funkcje (lub mieć globalne lub std:: funkcje, które mają wystąpień kontenera jako parametry).

Funkcje te muszą zwracać ten sam typ (zwykle container::iterator, ale jest to tylko konwencja). Zwrócony typ musi implementować operator*, operator++ i operator!=.