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 开发者_如何学Pythoncustom 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?
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.
You have two choices:
- you provide member functions named
begin
andend
that can be called likeC.begin()
andC.end()
; - otherwise, you provide free functions named
begin
andend
that can be found using argument-dependent lookup, or in namespacestd
, and can be called likebegin(C)
andend(C)
.
As others have stated, your container must implement begin()
and end()
functions (or have global or std::
functions that take instances of your container as parameters).
Those functions must return the same type (usually container::iterator
, but that is only a convention). The returned type must implement operator*
, operator++
, and operator!=
.
To my knowledge SomeSortedContainer
just needs to provide begin()
and end()
. And these should return a standard compliant forward iterator, in your case SomeSortedContainerIterator
, which would actually wrap a std::vector<Type>::iterator
. With standard compliant I mean it has to provide the usual increment and dereferencing operators, but also all those value_type
, reference_type
, ... typedefs, which in turn are used by the foreach construct to determine the underlying type of the container elements. But you might just forward them from the std::vector<Type>::iterator
.
精彩评论