I have a Red Black tree implemented in c++. It supports the functionality of a STL map. Tree nodes contain keys and the values mapped. I want to write an iterator class for this, but I'm stuck with how to do it. Should I make it an inner class of the Tree class? Can anyone give me some guidelines on how to write it + some resources??
Thank You!!
Sure, read this nice article on writing STL iterators, it might give you the needed overview:
http://www.drdobbs.com/184401417
In general, yes, an inner class is good, because the iterator needs access to your implementation specific tree nodes:
struct container { ...
public:
struct iterator {
// these typedefs are needed if you want to be STL compatible
typedef std::forward_iterator_tag iterator_category;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
// the element points to your implementation node
iterator( element* init = 0 ) : current(init) {}
T& operator*() { return current->data; } // dereference
const T& operator*() const { return current->data; }
iterator& operator++() { // prefix
if ( current ) current = current->next;
return *this;
}
iterator operator++(int) { // postfix
iterator temp = *this;
++*this;
return temp;
}
bool operator==(const iterator& x) const { return current == x.current; }
bool operator!=(const iterator& x) const { return current != x.current; }
private:
// the element points to your implementation node
element* current;
}
...
The good thing here is that while the iterator is public, the element can still stay private :). And yes, the code above is STL compilant too!
I thought I would add my own little batch of advice.
The first thing I'd like to note is that iterator and const_iterator are very likely to have much of their implementation in common. However, even though their code is similar, it's not exactly identical. This begs for templates.
The second thing I'd like to note is that a const_iterator should be constructible from an iterator (implicitly), but not the other way around.
The third thing I'd like to note is that if you wish to have a map-like interface, then you need to provide a reverse_iterator and const_reverse_iterator as well.
From a style point of view, I tend not to put the implementation of the iterator itself right in the class. I find it unreadable when the class implementation is cluttered with so much code that you struggle to see the types and methods available. For this reason I would recommend putting the implementation outside the class.
Finally, I definitely recommend Boost.Iterator. You may not use it, but read the material, it'll notably give you insight on how to write the code once and use it for the 4 kinds!
Quick illustration:
namespace detail {
template <class Value> class base_iterator;
}
template <class Value>
class container
{
public:
typedef detail::base_iterator<Value> iterator;
typedef detail::base_iterator<Value const> const_iterator;
typedef boost::reverse_iterator<iterator> reverse_iterator;
typedef boost::reverse_iterator<const_iterator> const_reverse_iterator;
};
I don't know about you, but I feel good when I do only a quarter of the work and leverages a compiler/library to fill in the rest for me :)
The iterator class needs to be either a nested class, or at least a typedef that aliases your_map::iterator to some type that's defined elsewhere. A nested class is usually the cleanest/easiest route though.
As far as resources go, one possible source of help would be the Boost::iterator library, which includes components intended to make iterators easier to implement.
Related
I have a container which is responsible for managing a set of attributes. The class partially looks something like this:
class AttributeSet
{
public:
// ... interface is irrelevant for my question.
private:
std::vector<boost::shared_ptr<Attribute> > m_attributes;
};
Attribute is polymorphic so the attributes have to be stored as pointers however they can never be NULL.
I want to use this class with BOOST_FOREACH, like this:
BOOST_FOREACH(const Attribute &attribute, attributeSet)
{
...
}
According to BOOST_FOREACH documentation,
The support for STL containers is very general; anything that looks like an STL container counts. If it has nested iterator and const_iterator types and begin() and end() member functions, BOOST_FOREACH will automatically know how to iterate over it.
So I updated my class to look something like this:
class AttributeSet
{
public:
typedef std::vector<boost::shared_ptr<Attribute> > container;
typedef container::iterator iterator;
typedef container::const_iterator const_iterator;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
private:
container m_attributes;
};
So now I can do this:
BOOST_FOREACH(const boost::shared_ptr<Attribute> &attribute, attributeSet)
{
...
}
This is nice however I don't like that it exposes the attributes as pointers. From the caller side, this is noise and would generate pointless NULL checks.
I have a few ideas on how to correct the problem. For example, something like this would be nice:
class AttributeSet
{
public:
typedef std::vector<boost::shared_ptr<Attribute> > container;
typedef iterator_dereference_adapter< container::iterator > iterator;
typedef iterator_dereference_adapter< container::const_iterator > const_iterator;
iterator begin() { return iterator(m_attributes.begin()); }
iterator end() { return iterator(m_attributes.end()); }
const_iterator begin() const { return const_iterator(m_attributes.begin()); }
const_iterator end() const { return const_iterator(m_attributes.end()); }
private:
container m_attributes;
};
The 'iterator_dereference_adapter' class is somewhat self-explanatory. It would wrap an existing iterator of pointers and dereference the pointer values.
So finally, my question...
Before I go off and try to write this adapter, is there something in STL or Boost like this class?
I'm open to other ideas.
Boost has indirect_iterator which is exactly inteded for wrapping an iterator to pointer type and automatically dereferencing.
I have a little problem while trying to implement a container, Set, based on a linked list.
Yeah, I know that there's an STL implementation of a set, but this is for homework. :)
So, this is what I have done so far:
my Set.h file looks like that:
template <class T>
class Set {
private:
typedef std::list<T> base_container;
base_container items;
public:
class myIterator {
public:
typename base_container::iterator base_iterator;
myIterator() { }
};
void addItem(const T item) {
items.push_back(item);
}
typedef typename Set<T>::myIterator setIterator;
setIterator begin() { return items.begin(); }
setIterator end() { return items.end(); }
Set<T>(void) { }
~Set<T>(void) { }
};
Now, main.cpp:
#include "Set.h"
int main(void) {
Set<int> mySet;
mySet.addItem(1);
mySet.addItem(2);
mySet.addItem(3);
mySet.addItem(4);
Set<int>::myIterator x;
x = mySet.begin(); // produces an error about non-convertible types.
return EXIT_SUCCESS;
}
The error is as follows:
error C2664: 'Set<T>::myIterator::myIterator(const Set<T>::myIterator &)' : cannot convert parameter 1 from 'std::_List_iterator<_Mylist>' to 'const Set<T>::myIterator &'
Clearly I messed things up, but I'm not sure which part of the code is actually the problem.
Any suggestions about how to fix this? Any helpful information will be appreciated.
Thanks. :)
There are many problems with your approach.
As others have said, you can't create your iterator type from the underlying type:
setIterator begin() { return items.begin(); }
setIterator end() { return items.end(); }
This can be solved by adding a constructor to your type:
class myIterator {
typedef typename base_container::iterator base_iterator_type;
public:
explicit myIterator(base_iterator_type i) : base_iterator(i) { }
base_iterator_type base_iterator;
myIterator() { }
};
This constructor should be explicit, which means you need to change how you create it:
setIterator begin() { return setIterator(items.begin()); }
The next problem is that your type doesn't implement the iterator interface, it doesn't provide operator++ or operator* etc. and it doesn't define nested types such as value_type and iteratory_category i.e. it's not an iterator (just giving it a name with "iterator" in it doesn't make it true!)
Once you fix that and your type is a valid iterator, you'll find your container can't be used with STL-style algorithms because it doesn't implement the container requirements. Among other things, it should provide a nested type called iterator not setIterator so that other template code can use S::iterator without caring if S is a std::set<T> or a Set<T>. Don't call it Set<T>::setIterator, just call it Set<T>::iterator. Also in this case there's no point defining myIterator (noone cares that it's yours! :-) then having a typedef to call it setIterator, just name the type with the right name in the first place and you don't need a typedef.
The problem is here:
setIterator begin() { return items.begin(); }
setIterator end() { return items.end(); }
The values you're trying to return have the wrong type. They are of type base_iterator and not setIterator, and there's no way to implicitly convert from the former to the latter.
You can derive from std::iterator<T> and provide the approprate iterator category tag. This will automatically give your iterator the required nested types such as value_type in terms of T. You will still need to write function members such as operator++ and operator* (depending on your iterator category, e.g. you also need operator[] for random access iterators)
A set of APIs that I commonly use follow a linked-list pattern:
struct SomeObject
{
const char* some_value;
const char* some_other_value;
SomeObject* next;
}
LONG GetObjectList( SomeObject** list );
void FreeObjectList( SomeObject* list );
This API is not mine and I cannot change it.
So, I'd like to encapsulate their construction/destruction, access, and add iterator support. My plan is to do something like this:
/// encapsulate access to the SomeObject* type
class MyObject
{
public:
MyObject() : object_( NULL ) { };
MyObject( const SomeObject* object ) : object_( object ) { };
const char* SomeValue() const
{
return NULL != object_ ? object_->some_value : NULL;
};
const char* SomeValue() const
{
return NULL != object_ ? object_->some_other_value : NULL;
};
private:
SomeObject* object_;
}; // class MyObject
bool operator==( const MyObject& i, const MyObject& j )
{
return // some comparison algorithm.
};
/// provide iterator support to SomeObject*
class MyObjectIterator
: public boost::iterator_adaptor< MyObjectIterator,
MyObject*,
boost::use_default,
boost::forward_traversal_tag >
{
public:
// MyObjectIterator() constructors
private:
friend class boost::iterator_core_access;
// How do I cleanly give the iterator access to the underlying SomeObject*
// to access the `next` pointer without exposing that implementation detail
// in `MyObject`?
void increment() { ??? };
};
/// encapsulate the SomeObject* creation/destruction
class MyObjectList
{
public:
typedef MyObjectIterator const_iterator;
MyObjectList() : my_list_( MyObjectList::Create(), &::FreeObjectList )
{
};
const_iterator begin() const
{
// How do I convert a `SomeObject` pointer to a `MyObject` reference?
return MyObjectIterator( ??? );
};
const_iterator end() const
{
return MyObjectIterator();
};
private:
static SomeObject* Create()
{
SomeObject* list = NULL;
GetObjectList( &list );
return list;
};
boost::shared_ptr< void > my_list_;
}; // class MyObjectList
My two questions are:
How do I cleanly give MyObjectIterator access to the underlying SomeObject to access the next pointer in the linked list without exposing that implementation detail in MyObject?
In MyObjectList::begin(), how do I convert a SomeObject pointer to a MyObject reference?
Thanks,
PaulH
Edit: The linked-list APIs I'm wrapping are not mine. I cannot change them.
First, of course, for real use, you almost certainly shouldn't be writing your own linked list or iterator at all. Second, good uses for linked lists (even one that's already written, debugged, etc.) are also pretty rare -- except in a few rather unusual circumstances, you should probably use something else (most often vector).
That said, an iterator is typically a friend (or nested class) of the class to which it provides access. It provides the rest of the world with an abstract interface, but the iterator itself has direct knowledge of (and access to) the internals of the linked list (or whatever container) to which it provides access). Here's a general notion:
// warning: This is really pseudo code -- it hasn't been tested, and would
// undoubtedly require a complete rewrite to even compile, not to mention work.
template <class T>
class linked_list {
public:
class iterator;
private:
// A linked list is composed of nodes.
// Each node has a value and a pointer to the next node:
class node {
T value;
node *next;
friend class iterator;
friend class linked_list;
public:
node(T v, node *n=NULL) : value(v), next(n) {}
};
public:
// An iterator gives access to the linked list.
// Operations:
// increment: advance to next item in list
// dereference: access value at current position in list
// compare: see if one iterator equals another
class iterator {
node *pos;
public:
iterator(node *p=NULL) : pos(p) {}
iterator operator++() {
assert(pos);
pos = pos->next;
return *this;
}
T operator*() { return pos->value; }
bool operator!=(iterator other) { return pos != other.pos; }
};
iterator begin() { return iterator(head); }
iterator end() { return iterator(); }
void push_front(T value) {
node *temp = new node(value, head);
head = temp;
}
linked_list() : head(NULL) {}
private:
node *head;
};
To work along with the algorithms in the standard library, you have to define quite a bit more than this tried to (e.g., typedefs like value_type and reference_type). This is only intended to show the general structure.
My advice: Trash this and use an existing slist<> implementation. IIRC, it will be in C++1x, so your compiler(s) might already support it. Or it might be in boost. Or take it from someplace else.
Wherever you get it from, what you get has all these problems already solved, is likely very well tested, therefore bug-free and fast, and the code using it is easily recognizable (looking at it many of us would immediately see what it does, because it's been around for a while and it's going to to be part of the next standard).
The last time I wrote my own list class was before the STL became part of the C++ standard library.
Ok, since you're stuck with the API you have, here's something that might get you started:
class MyObjectList
{
public:
typedef SomeObject value_type;
// more typedefs
class iterator {
public:
typedef SomeObject value_type;
// more typedefs
iterator(SomeObject* pObj = NULL)
: pObj_(pObj) {}
iterator& operator++() {if(pObj_)pObj_ = pObj_->next;}
iterator operator++(int) {iterator tmp(*this);
operator++();
return tmp;}
bool operator==(const iterator& rhs) const
{return pObj_ == rhs.pObj_;}
bool operator!=(const iterator& rhs) const
{return !operator==(rhs);}
value_type& operator*() {return pObj_;}
private:
SomeObject* pObj_;
};
class const_iterator {
public:
typedef SomeObject value_type;
// more typedefs
const_iterator(const SomeObject* pObj = NULL)
: pObj_(pObj) {}
iterator& operator++() {if(pObj_)pObj_ = pObj_->next;}
iterator operator++(int) {iterator tmp(*this);
operator++();
return tmp;}
bool operator==(const iterator& rhs) const
{return pObj_ == rhs.pObj_;}
bool operator!=(const iterator& rhs) const
{return !operator==(rhs);}
const value_type& operator*() {return pObj_;}
private:
const SomeObject* pObj_;
};
MyObjectList() : list_() {GetObjectList(&list_;);}
~MyObjectList() {FreeObjectList(list_);}
iterator begin() {return list_ ? iterator(list_)
: iterator();}
const_iterator begin() const {return list_ ? const_iterator(list_)
: const_iterator();}
iterator end () {return iterator(getEnd_());}
const_iterator end () const {return const_iterator(getEnd_());}
private:
SomeObject* list_;
SomeObject* getEnd_()
{
SomeObject* end = list_;
if(list_)
while(end->next)
end = end->next;
return end;
}
};
Obviously, there's more to this (for example, I believe const and non-const iterators should be comparable, too), but that shouldn't be hard to add to this.
From what you said, you probably have a BIG legacy code using your struct SomeObject types but you want to play nicely with new code and use iterators/stl containers.
If that's the case, you will not be able to (in an easy way) use your new created iterator in all the legacy code base, since that will be changing a lot of code, but, you can write a templated iterator that, if your structs follow the same pattern, having a next field, will work.
Something like this (I haven't tested nor compiled it, it's just an idea):
Suppose you have your struct:
struct SomeObject
{
SomeObject* next;
}
You will be able to create something like this:
template <class T>
class MyIterator {
public:
//implement the iterator abusing the fact that T will have a `next` field, and it is accessible, since it's a struct
};
template <class T>
MyIterator<T> createIterator(T* object) {
MyIterator<T> it(object);
return it;
}
If you implement your iterator correctly, you will be able to use all the STL algorithms with your old structs.
PS.: If you're in a scenario of some legacy code with this kind of structs, I do too, and I implemented this workaround. It works great.
You would make MyObjectIterator a friend of MyObject. I don't see any better way. And really I think it's reasonable that iterators get whatever special friend access is necessary for them to perform their duties.
You don't seem to have considered how and where your MyObject instance are going to be stored. Or perhaps that's what this question is coming out of. It seems like you would have to have a separate linked list of MyObjects in your MyObjectList. Then at least MyObjectList::begin() can just grab the first MyObject of your internal linked list of them. And if the only operations that may modify or rearrange this list only ever happen through the iterators you provide, then you can problem keep these lists in synch without too much trouble. Otherwise, if there are functions in the API you're using that take the raw SomeObject linked list and manipulate it, then you may have trouble.
I can see why you've tried to design this scheme, but having separate MyObjects that point to SomeObjects even through SomeObjects themselves make up the real list structure.... That is not an easy way to wrap a list.
The simplest alternative is just to do away with MyObject completely. Let your iterators work against SomeObject instances directly and return those when dereferenced. Sure that does expose SomeObject to the outside, particularly its next member. But is that really a big enough problem to justify a more complex scheme to wrap it all up?
Another way to deal with might be to have MyObject privately inherit from SomeObject. Then each SomeObject instance can be downcast as a reference to a MyObject instance and given to the outside world that way, thus hiding the implemtation details of SomeObject and only exposing the desired public member functions. The standard probably doesn't guarantee this will work, but in practice since they'll likely have the exact same memory layouts you may be able to get away with it. However, I'm not sure that I would actually ever try such a thing in a real program unless absolutely necessary.
The last alternative I can think of is just to transfer the data into a list of more convenient data structures after being given to you by this API. And then of course transfer it back into a raw SomeObject list only if necessary to pass it back to the API. Just make your own SomeObjectData or whatever to store the strings and put them in a std::list. Whether or not this is actually feasible for you really depends on how this data is used in the context of the API you've mentioned. If there are other API functions that modify SomeObject lists and you need to use them frequently, then constantly converting SomeObject lists to and from std::list<SomeObjectData> could be annoying.
I've seen some very good answers so far but I fear they might be "bare".
Before blindingly charge in let's examine the requirements.
As you noticed the structure is similar to a singly linked list, the C++0x standard defines such a structure, called forward_list. Read up its interface, yours should come close.
The iterator type will be ForwardIterator.
I would like to expose one very annoying fact though: who's responsible for the memory ?
I am worried because there's no copy facility in the interface you've provided, so should we disable the copy constructor and assignment operator of our new list class ?
Implementation is easy, there's enough on this page even though the iterator don't properly implement the iterator traits in general, but I would consider ditching this idea completely and move on to a better scheme:
class MyObject { public: ... private: SomeObject mData; };
Wrapping up GetObjectList and returning a deque<MyObject>, I guess the LONG returns the number of items ?
I'd like to design a class Foo that stores various data of different types and returns iterators over them. It's supposed to be generic, so the user of Foo does not know how the data is stored (Foo could be using std::set or std::vector or whatever).
I'm tempted to write an interface like this:
class Foo {
class FooImpl;
FooImpl* impl_;
public:
const Iterator<std::string>& GetStrings() const;
const Iterator<int>& GetInts() const;
};
where Iterator is something like this (like iterators in .NET):
template<class T>
class Iterator {
public:
const T& Value() const = 0;
bool Done() const = 0;
void Next() = 0;
};
But I know that kind of iterator is not standard in C++, and it's better to use iterators the way the STL does, so you can use the STL algorithms on them.
How can I do that? (Do I need iterator_traits by any chance?)
Do you understand why the STL chose to put iterator implementation details in the header file? JIT frameworks are able to inline across compilation units, but C++ can only inline within a compilation unit. Advancing through a sequence is much faster when inlined, the cost of a function call dominates actually traversing the data structure.
If you really want to hide the implementation details, go ahead. You could make an STL-compatible iterator that implements operator++ and operator!= and operator-> in terms of protected virtual functions, the Next, Done, and Value you've mentioned would be decent names. Just expect to pay for the encapsulation with lower performance.
A c++ class with iterators has to provide at least two functions if they have to work with the std library
iterator begin() //returns an iterator at starting pos
iterator end() //returns an iterator one past end or just invald
The iterator has to overload the increment operators, equals and *
iterator operator++()
iterator operator==()//make sure that an invalid iterator equals end()
T& operator*()
You can use the iterator class to wrap around the iterator of the internal storage to ensure that the user is limited to these methods.
template <typename T> iter
{
iter(T::iterator& intern)
T::value_type& operator*(){return *intern}
iter operator++(){return iter(++intern);}
bool operator==(iter const& other)const{return intern == other.intern;}
}
Where T is the type of your container.(The class is incomplete and I may have mixed something up)
It almost looks like you're trying to create container-independent code, which is not (in general) a good idea, unless you are writing an algorithm which can operate solely with iterators. (See Scott Myers Effective STL Item 2: Beware the illusion of container-independent code)
The problem is that most of the standard containers do not provide overlapping functionality. If you're writing code for a particular container, assume you're writing code for that container. Don't bother trying to make it container-independent.
Use a typedef to return an boost::iterator_range. For example (never mind the names),
class Container
{
typedef std::vector<int> Collection;
public:
typedef boost::iterator_range<Collection::iterator> CollectionRange;
typedef Collection::iterator CollectionIterator;
Range range() const {
return make_iterator_range(collection_.begin(), collection_.end());
}
private:
Collection collection_;
};
The user code will be
Container c;
// ...
FOREACH(int i, c.range()) { //... }
Container::Range r = c.range();
for(Container::iterator j = r.begin(); j!= r.end(); j++) { // ... }
This is not generic, but the same idea can be used with templates.
To fulfill the requirement that the particular container (vector, set, ...) is not mentioned in the header file, and the user will be able to iterate over all strings, is to use the visitor pattern. The downside, of course, is that the user won't be able to use the STL algorithms on the strings.
// foo.h
class StringVisitor {
public:
void accept(const std::string& str) {
std::cout << str << std::endl;
}
};
class Foo {
class Impl;
Impl* impl_;
public:
Foo();
~Foo();
void VisitStrings(StringVisitor v) const;
};
// foo.cc
class Foo::Impl {
typedef std::vector<std::string> StringContainer;
StringContainer str_;
public:
Impl() {
str_.push_back("a");
str_.push_back("b");
}
void VisitStrings(StringVisitor v) const {
for(StringContainer::const_iterator it = str_.begin();
it != str_.end(); ++it){
v.accept(*it);
}
}
};
Foo::Foo() : impl_(new Impl()) {}
Foo::~Foo() {delete impl_;}
void Foo::VisitStrings(StringVisitor v) const {
impl_->VisitStrings(v);
}
// main.cc
int main() {
Foo foo;
foo.VisitStrings(StringVisitor());
return 0;
}
Having toyed with this I suspect it isn't remotely possible, but I thought I'd ask the experts. I have the following C++ code:
class IInterface
{
virtual void SomeMethod() = 0;
};
class Object
{
IInterface* GetInterface() { ... }
};
class Container
{
private:
struct Item
{
Object* pObject;
[... other members ...]
};
std::list<Item> m_items;
};
I want to add these methods to Container:
MagicIterator<IInterface*> Begin();
MagicIterator<IInterface*> End();
In order that callers can write:
Container c = [...]
for (MagicIterator<IInterface*> i = c.Begin(); i != c.End(); i++)
{
IInterface* pItf = *i;
[...]
}
So essentially I want to provide a class which appears to be iterating over some collection (which the caller of Begin() and End() is not allowed to see) of IInterface pointers, but which is actually iterating over a collection of pointers to other objects (private to the Container class) which can be converted into IInterface pointers.
A few key points:
MagicIterator is to be defined outside Container.
Container::Item must remain private.
MagicIterator has to iterate over IInterface pointers, despite the fact that Container holds a std::list<Container::Item>. Container::Item contains an Object*, and Object can be used to fetch IInterface*.
MagicIterator has to be reusable with several classes which resemble Container, but might internally have different list implementations holding different objects (std::vector<SomeOtherItem>, mylist<YetAnotherItem>) and with IInterface* obtained in a different manner each time.
MagicIterator should not contain container-specific code, though it may delegate to classes which do, provided such delegation is not hard coded to to particular containers inside MagicIterator (so is somehow resolved automatically by the compiler, for example).
The solution must compile under Visual C++ without use of other libraries (such as boost) which would require a license agreement from their authors.
Also, iteration may not allocate any heap memory (so no new() or malloc() at any stage), and no memcpy().
Thanks for your time, even if you're just reading; this one's really been bugging me!
Update: Whilst I've had some very interesting answers, none have met all the above requirements yet. Notably the tricky areas are i) decoupling MagicIterator from Container somehow (default template arguments don't cut it), and ii) avoiding heap allocation; but I'm really after a solution which covers all of the above bullets.
I think you have two separate issues here:
First, create an iterator that will return the IInterface* from your list<Container::Item>. This is easily done with boost::iterator_adaptor:
class cont_iter
: public boost::iterator_adaptor<
cont_iter // Derived
, std::list<Container::Item>::iterator // Base
, IInterface* // Value
, boost::forward_traversal_tag // CategoryOrTraversal
, IInterface* // Reference :)
>
{
public:
cont_iter()
: cont_iter::iterator_adaptor_() {}
explicit cont_iter(const cont_iter::iterator_adaptor_::base_type& p)
: cont_iter::iterator_adaptor_(p) {}
private:
friend class boost::iterator_core_access;
IInterface* dereference() { return this->base()->pObject->GetInterface(); }
};
You would create this type as inner in Container and return in from its begin() and end() methods.
Second, you want the runtime-polymorphic MagicIterator. This is exactly what any_iterator does. the MagicIterator<IInterface*> is just any_iterator<IInterface*, boost::forward_traversal_tag, IInterface*>, and cont_iter can be just assigned to it.
Create an abstract IteratorImplementation class:
template<typename T>
class IteratorImplementation
{
public:
virtual ~IteratorImplementation() = 0;
virtual T &operator*() = 0;
virtual const T &operator*() const = 0;
virtual Iterator<T> &operator++() = 0;
virtual Iterator<T> &operator--() = 0;
};
And an Iterator class to wrap around it:
template<typename T>
class Iterator
{
public:
Iterator(IteratorImplementation<T> * = 0);
~Iterator();
T &operator*();
const T &operator*() const;
Iterator<T> &operator++();
Iterator<T> &operator--();
private:
IteratorImplementation<T> *i;
}
Iterator::Iterator(IteratorImplementation<T> *impl) :
i(impl)
{
}
Iterator::~Iterator()
{
delete i;
}
T &Iterator::operator*()
{
if(!impl)
{
// Throw exception if you please.
return;
}
return (*impl)();
}
// etc.
(You can make IteratorImplementation a class "inside" of Iterator to keep things tidy.)
In your Container class, return an instance of Iterator with a custom subclass of IteratorImplementation in the ctor:
class ObjectContainer
{
public:
void insert(Object *o);
// ...
Iterator<Object *> begin();
Iterator<Object *> end();
private:
class CustomIteratorImplementation :
public IteratorImplementation<Object *>
{
public:
// Re-implement stuff here.
}
};
Iterator<Object *> ObjectContainer::begin()
{
CustomIteratorImplementation *impl = new CustomIteratorImplementation(); // Wish we had C++0x's "var" here. ;P
return Iterator<Object *>(impl);
}
Doesn't sound too complicated. You can define the iterator outside. You can also use typedefs. Something like this would fit i think. Note that it would be way cleaner if that MagicIterator would be not a free template, but a member of Item, typedefed in Container maybe. As it's now, there is a cyclic reference in it, which make it necassary to write some ugly workaround code.
namespace detail {
template<typename T, typename U>
struct constify;
template<typename T, typename U>
struct constify<T*, U*> {
typedef T * type;
};
template<typename T, typename U>
struct constify<T*, U const*> {
typedef T const * type;
};
}
template<typename DstType,
typename Container,
typename InputIterator>
struct MagicIterator;
class Container
{
private:
struct Item
{
Object* pObject;
};
std::list<Item> m_items;
public:
// required by every Container for the iterator
typedef std::list<Item> iterator;
typedef std::list<Item> const_iterator;
// convenience declarations
typedef MagicIterator< IInterface*, Container, iterator >
item_iterator;
typedef MagicIterator< IInterface*, Container, const_iterator >
const_item_iterator;
item_iterator Begin();
item_iterator End();
};
template<typename DstType,
typename Container = Container,
typename InputIterator = typename Container::iterator>
struct MagicIterator :
// pick either const T or T, depending on whether it's a const_iterator.
std::iterator<std::input_iterator_tag,
typename detail::constify<
DstType,
typename InputIterator::value_type*>::type> {
typedef std::iterator<std::input_iterator_tag,
typename detail::constify<
DstType,
typename InputIterator::value_type*>::type> base;
MagicIterator():wrapped() { }
explicit MagicIterator(InputIterator const& it):wrapped(it) { }
MagicIterator(MagicIterator const& that):wrapped(that.wrapped) { }
typename base::value_type operator*() {
return (*wrapped).pObject->GetInterface();
}
MagicIterator& operator++() {
++wrapped;
return *this;
}
MagicIterator operator++(int) {
MagicIterator it(*this);
wrapped++;
return it;
}
bool operator==(MagicIterator const& it) const {
return it.wrapped == wrapped;
}
bool operator!=(MagicIterator const& it) const {
return !(*this == it);
}
InputIterator wrapped;
};
// now that the iterator adepter is defined, we can define Begin and End
inline Container::item_iterator Container::Begin() {
return item_iterator(m_items.begin());
}
inline Container::item_iterator Container::End() {
return item_iterator(m_items.end());
}
Now, start using it:
for(MagicIterator<IInterface*> it = c.Begin(); it != c.End(); ++it) {
// ...
}
You can also use a iterator mixin provided by boost, which works like the input version of boost::function_output_iterator. It calls your iterator's operator() which then returns the appropriate value, doing what we do above in our operator* in principle. You find it in random/detail/iterator_mixin.hpp. That would probably result in fewer code. But it also requires to wrack up our neck to ensure the friend-stuff because Item is private and the iterator isn't defined inside Item. Anyway, good luck :)
It really depends on the Container, because the return values of c.Begin() and c.End() are implementation-defined.
If a list of possible Containers is known to MagicIterator, a wrapper class could be used.
template<typename T>
class MagicIterator
{
public:
MagicIterator(std::vector<T>::const_iterator i)
{
vector_const_iterator = i;
}
// Reimplement similarly for more types.
MagicIterator(std::vector<T>::iterator i);
MagicIterator(std::list<T>::const_iterator i);
MagicIterator(std::list<T>::iterator i);
// Reimplement operators here...
private:
std::vector<T>::const_iterator vector_const_iterator;
std::vector<T>::iterator vector_iterator;
std::list<T>::const_iterator list_const_iterator;
std::list<T>::iterator list_iterator;
};
The easy way would be to use a template which accepts Container's type:
// C++0x
template<typename T>
class Iterator :
public T::iterator
{
using T::iterator::iterator;
};
for(Iterator<Container> i = c.begin(); i != c.end(); ++i)
{
// ...
}
More information here.
I see no reason why you can't implement this exactly as you've laid it out... am I missing something?
To clarify, you'll need to put some kind of accessor methods on your Container class. They can be private and you can declare MagicIterator as a friend, if you feel that's the best way to encapsulate it, but I'd expose them directly. These accessor methods would use a normal STL iterator inside Container and perform the conversion to IInterface. Thus the iterating would actually be done with the Container's accessor methods and MagicIterator would just be a kind of proxy object to make it easier. To make it reentrant, you could have the MagicIterator pass in some kind of ID to look up the STL iterator inside Container, or you could actually have it pass in the STL iterator as a void *.
I've now found a solution which is fitter for my original purpose. I still don't like it though :)
The solution involves MagicIterator being templated on IInterface* and being constructed with both a void* to an iterator, the byte size of said iterator, and a table of pointers to functions which perform standard iteration functions on said void* such as increment, decrement, dereference, etc. MagicIterator assumes that it is safe to memcpy the given iterator into an internal buffer, and implements its own members by passing its own buffer as a void* to the supplied functions as if it were the original iterator.
Container then has to implement static iteration functions which cast back a supplied void* to a std::list::iterator. Container::begin() and Container::end() simply construct a std::list::iterator, pass a pointer to it into a MagicIterator along with a table of its iteration functions, and return the MagicIterator.
It's somewhat disgusting, and breaks my original rule regarding "no memcpy()", and makes assumptions about the internals of the iterators in question. But it avoids heap allocation, keeps Collection's internals (including Item) private, renders MagicIterator entirely independent of the collection in question and of IInterface*, and in theory allows MagicIterators to work with any collection (provided its iterators can be safely memcopy()'d).
A visitor may be a simpler (and therefore easier to maintain) solution.