Generic design mixed with curiously recurring template pattern. C++ - c++

Consider this kind of problem. I have a Base class and three classes derived from Base. For instance: DerivedA, DerivedB and DerivedC. Each derived class has its unique container. Hence DerivedA has std::vector<int>, DerivedB has std::set<int> and DerivedC has std::map<int, std::string>. And I want an interface in Base to access the container of derived class on which it is currently pointed to.
Base* d1 = new DerivedA;
for(std::vector<int>::iterator iter = d1->begin(); iter != d1->end(); ++iter)
{
//processing
}
I tried to wrap each container to separate class and keep a pointer of their base
in the Base class.
class CollA;
template<class T>
class traits;
template<>
class traits<CollA>
{
public:
typedef vector<int> container;
};
template<class T>
class Coll
{
public:
typedef typename traits<T>::container container;
typename container::iterator begin() const
{
}
};
class CollA : public Coll<CollA>
{
typedef traits<CollA>::container container;
public:
container::iterator begin()
{
return V.begin();
}
private:
vector<int> V;
};
class Base
{
public:
Base()
{
}
// what to do here? I must keep a pointer to Coll; But Coll itself is a template
};
Suggest me something. I am kind of lost in this horrible design.

In order to do what you want, you need to define a common type of iterator that can be returned from the different begin() and end() overrides in the derived classes.
Before that, of course, you need to decide what exactly you want that iterator to do, as Yakk explained in his comment. For starters, you need to decide what value_type will result from indirecting through such an iterator. The only common type that I can think of given your three different containers is const int, as keys in std::maps are const and std::set iterators are const iterators (since the elements are keys themselves). So, when iterating using the common iterator type, you'll only be able to observe the ints in there.
Now, the iterator implementation will need to call different code (at runtime) depending on the derived class from which it originated. This is a typical use case for type erasure. When done properly, this would allow you to wrap any kind of iterator, as long as it supports the interface you need. In your case however, you may not need to go that far, since I suppose you know the full set of containers you need to support, so the set of iterator types is well known and bounded as well.
This means you can use a boost::variant to store the wrapped iterator. This should be more efficient than a full type erasure solution, since it avoids some internal virtual function calls and possibly some heap allocations (unless the type erasure solution can use some kind of small object optimization, which is fairly possible for iterators, but is even more complicated to implement).
Here's a skeleton implementation of such an iterator, together with the class hierarchy using it and some simple test code. Note that I've only implemented the basic iterator functionality that's needed to make your loop work.
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <iterator>
#include "boost/variant.hpp"
//Helper function object types to implement each operator on the variant iterator.
struct indirection_visitor : boost::static_visitor<const int&>
{
const int& operator()(std::vector<int>::iterator i) const { return *i; }
const int& operator()(std::set<int>::iterator i) const { return *i; }
const int& operator()(std::map<int, std::string>::iterator i) const { return i->first; }
};
struct prefix_increment_visitor : boost::static_visitor<>
{
template<typename I> void operator()(I& i) const { ++i; }
};
//The iterator itself.
//It should probably hide the internal variant, in which case the non-member operators
//should be declared as friends.
struct var_iterator : std::iterator<std::bidirectional_iterator_tag, const int>
{
var_iterator() { }
template<typename I> var_iterator(I i) : it(i) { }
boost::variant<std::vector<int>::iterator, std::set<int>::iterator, std::map<int, std::string>::iterator> it;
const int& operator*() { return boost::apply_visitor(indirection_visitor(), it); }
var_iterator& operator++()
{
boost::apply_visitor(prefix_increment_visitor(), it);
return *this;
}
};
inline bool operator==(var_iterator i1, var_iterator i2) { return i1.it == i2.it; }
inline bool operator!=(var_iterator i1, var_iterator i2) { return !(i1 == i2); }
//Here's the class hierarchy.
//We use CRTP only to avoid copying and pasting the begin() and end() overrides for each derived class.
struct Base
{
virtual var_iterator begin() = 0;
virtual var_iterator end() = 0;
};
template<typename D> struct Base_container : Base
{
var_iterator begin() override { return static_cast<D*>(this)->container.begin(); }
var_iterator end() override { return static_cast<D*>(this)->container.end(); }
};
struct DerivedA : Base_container<DerivedA>
{
std::vector<int> container;
};
struct DerivedB : Base_container<DerivedB>
{
std::set<int> container;
};
struct DerivedC : Base_container<DerivedC>
{
std::map<int, std::string> container;
};
//Quick test.
void f(Base* bp)
{
for(auto iter = bp->begin(); iter != bp->end(); ++iter)
{
std::cout << *iter << ' ';
}
std::cout << '\n';
//We have enough to make range-based for work too.
for(auto i : *bp)
std::cout << i << ' ';
std::cout << '\n';
}
int main()
{
DerivedA da;
da.container = {1, 2, 3};
f(&da);
DerivedB db;
db.container = {4, 5, 6};
f(&db);
DerivedC dc;
dc.container = std::map<int, std::string>{{7, "seven"}, {8, "eight"}, {9, "nine"}};
f(&dc);
}
Implementation notes:
As mentioned above, this is not a complete bidirectional iterator; I chose that tag as the most powerful common iterator among your container types.
I compiled and (superficially) tested the code in Clang 3.6.0 and GCC 5.1.0 in C++11 mode, and in Visual C++ 2013, using boost 1.58.0.
The code works in C++14 mode as well in the compilers above (and also in Visual C++ 2015 CTP6), but needs a small change because of a bug in boost 1.58 (I'll have to report that), otherwise you'll get an ambiguity error. You need to remove the base class of indirection_visitor and let the return type of this visitor be determined automatically. This only works in C++14, as it uses decltype(auto) internally, and it's this new code that causes the ambiguity. Earlier versions of boost don't have this problem, but don't have autodetection of return types either.
In C++14 mode and boost 1.58, you can use generic lambdas to implement simple visitors like prefix_increment_visitor, which makes the code more straightforward.
I removed the comparison visitors from my first version of the code, as boost::variant already provides a default equality operator and it's enough for this case (the example is long enough as it is).
You can add const in the required places to get true const iterator behaviour if needed (qualify begin() and end(), use static_cast<const D*> in CRTP, declare the variant to contain const_iterators, adjust the visitor).
You can, of course, implement some sort of poor-man's variant and avoid using boost, but boost::variant makes everything much easier, cleaner and safer.

Related

C++ type punning with classes

I am writing some C++ code which wraps the std::unordered_map type, where I want to hide the underlying type and present it as another type. More specifically, I want to wrap the std::pair from the std::unordered_map with another type. For the sake of argument, lets suppose the wrapper looks like this...
template <typename ActualT >
class wrapper final
{
private:
ActualT actual_;
public:
//Some constructors...
typename ActualT::first_type & get_first()
{
return actual_.first;
}
typename ActualT::second_type & get_second()
{
return actual_.second;
}
};
My reasoning is that since the wrapper class only has a member which is the exact type which it is wrapping, converting a reference from the original type to the wrapper type should be fine, but the type compatibility for structs states that the members should have the same type and name for the types to be compatible. Would using type-punning in this fashion potentially cause undefined behaviour or alignment issues?
using my_map = std::unordered_map < int, int >;
my_map m;
//Do some inserts...
reinterpret_cast<wrapper<typename my_map::value_type>&>(*m.find(10)).get_second() = 1.0;
I want client code to be allowed to access the entries of a map without knowing about the pair which is returned by the map. I also want to write a custom forward iterator, hence I need to return a reference to the entry. Would converting the reference to the pair to a reference to a class which act as a wrapper be considered dangerous?
Is there perhaps a better approach to accomplishing this?
This absolutely is undefined behaviour.
Seriously rethink your priorities.
Some free functions of the form
const my_map::key_type & MeaningfulNameHere(my_map::reference)
will go a long way to giving you meaningful names.
If you must wrap the standard library with different names, just use a non-explicit constructor, and store references.
template <typename Map>
class entry final
{
private:
typename Map::reference ref;
public:
entry(Map::reference ref) : ref(ref) {}
const typename Map::key_type & key()
{
return ref.first;
}
typename Map::mapped_type & value()
{
return ref.second;
}
};
If you really need the iterator to dereference to entry you can. But you can just implicitly instantiate entrys from the Map::references returned by Map::iterator::operator*, you don't need a custom iterator.
template <typename Map>
class entry_iterator
{
private:
typename Map::iterator it;
entry<Map> entry;
public:
entry<Map>& operator*() { return entry; }
entry_iterator operator++() { ++it; entry = *it; return *this; }
// etc
}
So you could clean this up, but I wouldn't suggest it:
#include <unordered_map>
#include <iostream>
using namespace std;
template <class Key, class Value>
class wrapper
{
public:
explicit wrapper(std::pair<const Key, Value>& kvp)
: _key{kvp.first}
, _value{kvp.second}
{}
const Key& key() const { return _key; }
Value& value() { return _value; }
private:
const Key& _key;
Value& _value;
};
int main()
{
unordered_map<int,int> m;
m[1] = 1;
m[3] = 3;
auto it = m.find(1);
wrapper w{*it};
w.value() = 30;
std::cout << w.key() << " -> " << w.value() << '\n';
}
The above effectively hides the pair from users of your class. It doesn't deal with exceptions (find() returning end() for example), and makes no guarantees about lifetimes. It's marginally better than what you have because it doesn't require a reinterpret_cast to an unrelated type.
However, map, unordered_map, set, etc. storing returning iterators as pairs is just part of library -- it's the canonical form and I don't see the benefit of shielding people from it.

Abstract iterator for underlying collections

So basically what I want to do is to have a pure virtual method returning an iterator to an arbitrary collection of a concrete type, e.g in pseudo code:
virtual Iterator<T> getIterator() const = 0;
The user of this class actually don't care what implementation the child class uses. It could be a set, vector, list, array etc.
I'm aware of the std::iterator class but I cant find a way to specify it correctly in order to work with a simple vector.
virtual std::iterator<std::random_access_iterator_tag,T> getIterator() const = 0;
myVector.begin() // compilation error in implementation
defining std::iterator with const T as type parameter hasn't worked too. I also tried leaving T and instead defining the pointer and reference types as const T* and const T&.
By taking a look at the std::vector implementation, I found out that std::vector::const_iterator actually derives from _Iterator012 deriving from _Iterator_base.
It really bugs me that there isn't any way to work with arbitrary collections in std.
Implementing my classes as templates like in <algorithm> is not an option for me due two reasons:
No control over the actual value type
I simply don't want to make my classes templates complicating my design a lot and making things less flexible.
The used type parameter T was just for demonstration, actually this is a concrete type.
Here's a basic and very rudimentary skeleton approach using type erasure. You'll have to fill in a lot of missing details, though!
#include <memory>
template <typename T>
class TEIterator
{
struct TEImplBase
{
virtual ~TEImplBase() { }
virtual std::unique_ptr<TEImplBase> clone() const = 0;
virtual void increment() = 0;
virtual T & getValue() = 0;
T * getPointer() { return std::addressof(getValue()); }
};
template <typename Iter>
struct TEImpl
{
Iter iter;
TEImpl(Iter i) : iter(i) { }
virtual T & getValue()
{ return *iter; }
virtual std::unique_ptr<TEImplBase> clone() const
{ return std::unique_ptr<TEImplBase>(new TEImpl<Iter>(*this)); }
virtual void increment()
{ ++iter; }
};
std::unique_ptr<TEImplBase> impl;
public:
template <typename T>
TEClass(T && x)
: impl(new TEImpl<typename std::decay<T>::type>(std::forward<T>(x)))
{
}
TEClass(TEClass && rhs) = default;
TEClass(TEClass const & rhs) : impl(rhs.impl.clone()) { }
TEIterator & operator++()
{
impl->increment();
return *this;
}
T & operator*() { return impl->getValue(); }
T * operator->() { return impl->getPointer(); }
};
Usage:
std::vector<int> v;
std::deque<int> dq;
TEIterator<int> a = v.begin(), b = dq.end();
If you want to use a virtual method, you cannot use an arbitrary return value. What you can do, is define a base class, which is a wrapper around iterators, and subclass from that wrapper class.
But even then, you must restrict yourself to the smallest common denominator, since there are several iterator classes in the C++ standard library.
So, AFAICS, such a method with arbitrary iterators isn't really feasible without using templates.

Wrap STL vector and change behavior of its iterator

There is such code:
#include <iostream>
#include <vector>
template <class T>
class A{
public:
class iterator : public std::vector<T>::iterator{
public:
T& operator*(){
??
}
};
iterator begin(){
return v.begin(); // error
}
iterator end(){
return v.end(); // error
}
void add(const T& elem){
v.push_back(elem);
}
private:
std::vector<T> v;
};
int main() {
A<int> a;
a.add(2);
a.add(4);
for(A<int>::iterator it = a.begin(); it != a.end(); ++it){
std::cout << *it << std::endl;
}
return 0;
}
This is a wrapper for std::vector with my own additional functions. I would like to use std::vector's iterator, however I want only to change behavior of operator* for iterator:
T& operator*(){
// do some additional function
// normal behavior, return value of some element in vector
??
}
How can I use std::vector and its iterator with modification of only operator*? I would like also to wrap functions like begin() and end() for iterator, how to wrap them properly?
EDIT:
Using tips from answers in this topic, I managed to solve my problem in following way:
#include <iostream>
#include <vector>
template <class T>
class A {
public:
class iterator : public std::vector<T>::iterator {
public:
iterator(typename std::vector<T>::iterator c) : std::vector<T>::iterator(c) {
}
T& operator*() {
std::cout << "Im overloaded operator*\n";
return std::vector<T>::iterator::operator *();
}
};
iterator begin() {
return iterator(v.begin());
}
iterator end() {
return iterator(v.end());
}
void add(const T& elem) {
v.push_back(elem);
}
private:
std::vector<T> v;
};
int main() {
A<int> a;
a.add(2);
a.add(4);
for (A<int>::iterator it = a.begin(); it != a.end() ; ++it) {
std::cout << *it << std::endl;
}
return 0;
}
Maybe it will be helpful for someone.
Wrapping stdlib iterators is done best with iterator adaptors. This task is far from trivial and there is the Boost.Iterator library to simplify the task. Maybe one of the provided iterators already solves your problem.
If you are going to write this on your own (I really don't recommend this), you should implement your own iterator and have it be constructible from a vector::iterator, then overload all required operators to meet the requirements of the concept that your new iterator models. Also inherit from std::iterator to get the traits working. Don't forget to have the a const variant. This book has a chapter devoted to developing your own iterators. Also get a copy of the standard (C++03 or C++11, doesn't matter much here). You are going to need it.
Unfortunately, the only way to do this is to write a complete wrapper for std::vector and its iterator-types. This is a lot of work.
One does not inherit from std::vector<T>::iterator since it does not need to be a class. In some implementations this is just a typedef for T*, and one cannot inherit from a pointer. One also shouldn't inherit from standard containers as they lack a virtual destructor; a possibility is to inherit in a private or protected way and make all symbols and functions visible by means of typedef and using. In the end, you will have to rewrite the entire vector and its iterators that forward calls to the base implementation.
I think the answer here is most likely that you shouldn't change the behaviour of operator* for an iterator. Operator overloading should be done only in cases where it is so extremely intuitive that anyone reading the code that uses the operator would automatically know what is happening. An example of this would be if you had a matrix class and overloaded operator+. When someone sees you adding two matrix objects together, they can easily know what is happening.
When dereferencing an iterator however, there is no intuitive sense of what the additional side effects will be for your class.

How to return a generic iterator (independent of particular container)?

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

A C++ iterator adapter which wraps and hides an inner iterator and converts the iterated type

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.