Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++11 foreach syntax and custom iterator

I am writing an iterator for a container which is being used in place of a STL container. Currently the STL container is being used in many places with the c++11 foreach syntax eg: for(auto &x: C). We have needed to update the code to use a custom class that wraps the STL container:

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

How do I get auto to use the correct iterator for the custom container so the code is able to be called in the following way?:

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

In general what is required to ensure that auto uses the correct iterator for a class?

like image 618
shuttle87 Avatar asked Sep 26 '11 23:09

shuttle87


People also ask

Are iterators used in for each loops C++?

Working of the foreach loop in C++ So basically a for-each loop iterates over the elements of arrays, vectors, or any other data sets. It assigns the value of the current element to the variable iterator declared inside the loop.

What is foreach loop in C?

The working of foreach loops is to do something for every element rather than doing something n times. There is no foreach loop in C, but both C++ and Java have support for foreach type of loop. In C++, it was introduced in C++ 11 and Java in JDK 1.5. 0 The keyword used for foreach loop is “for” in both C++ and Java.

How do I make an iterator in C++?

IntegersType::iterator begin() { return m_data. begin(); } IntegersType::iterator end() { return m_data. end() } private: IntegersType m_data; }; The code above works because all containers in the C++ Standard Library do what we have done with our Integer container: they all implement their iterators as class members.


2 Answers

To be able to use range-based for, your class should provide const_iterator begin() const and const_iterator end() const members. You can also overload the global begin function, but having a member function is better in my opinion. iterator begin() and const_iterator cbegin() const are also recommended, but not required. If you simply want to iterate over a single internal container, that's REALLY easy:

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

If you want to iterate over anything custom though, you'll probably have to design your own iterators as classes inside your container.

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

For more details on writing an iterator class, see my answer here.

like image 81
Mooing Duck Avatar answered Oct 20 '22 22:10

Mooing Duck


You have two choices:

  • you provide member functions named begin and end that can be called like C.begin() and C.end();
  • otherwise, you provide free functions named begin and end that can be found using argument-dependent lookup, or in namespace std, and can be called like begin(C) and end(C).
like image 34
R. Martinho Fernandes Avatar answered Oct 20 '22 21:10

R. Martinho Fernandes