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).
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.