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.
Related
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.
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)
As far as I can tell in c++ there is no common base class that covers both iterator and reverse_iterator.
The only suggestion I have seen so far is to get around this using templates (
How to write a function that takes an iterator or collection in a generic way? )
However this solution doesn't seem to work for me.
class MyClass
{
template<typename Iter> Iter* generate_iterator(...params...)
{
//returns either a vector::iterator or vector::reverse_iterator
}
template<typename Iter> void do_stuff(Iter *begin, Iter *end)
{
//does stuff between elements specified by begin and end
//I would like this function to remain agnostic of which direction it is working in!
}
void caller()
{
//I would like this function to remain agnostic of which direction it is working in too...
do_stuff(generate_iterator(blah),generate_iterator(foo));
}
};
In this case, generate_iterator() cannot be used as desired because the compiler complains "generate_iterator is not a member of class MyClass" presumably because I haven't specified it (which I can't in practice as caller should be agnostic of the iterator type).
Can anyone help? Thanks in advance!
edit: as Mark B pointed out generate_iterator must return a pointer - now corrected
update: just started using this http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/start_page.html and it seems to work...
You can create your own iterator class that knows how to go both directions. Encapsulate both types of iterator and internally select whichever one you were initialized with.
Here's a start:
template<typename Container>
class BiIterator
{
public:
BiIterator(Container::iterator i) : m_fwd(i), m_isforward(true) {}
BiIterator(Container::reverse_iterator i) : m_rev(i), m_isforward(false) {}
bool operator==(const BiIterator & left, const BiIterator & right);
Container::value_type & operator*()
{
if (m_isforward)
return *m_fwd;
return *m_rev;
}
const Container::value_type & operator*() const;
BiIterator & operator++()
{
if (m_isforward)
++m_fwd;
else
++m_rev;
return *this;
}
private:
Container::iterator m_fwd;
Container::reverse_iterator m_rev;
bool m_isforward;
};
In C++ you can't write a function that returns two different types. In your template case it will return one or the other depending on the instantiation. You could possibly return a base pointer to a polymorphic iterator but that would cause me to ask what you're really trying to do here. Even the standard containers don't try to do that: They have begin and rbegin to distinguish properly. I would suggest having two separate functions that each do the right thing and return one type of iterator or the other as context dictates.
As a side, note that you can't implicitly determine a template instantiation of a type that's only used for the return type of a function.
By using boost tuple and boost any , your problem can be easily solved. I wrote a example by using boost::any , see below:
#include <boost/any.hpp>
using boost::any_cast;
#define MSG(msg) cout << msg << endl;
boost::any getIterator(std::vector<int>& vec, bool bReverse)
{
if(!bReverse)
return boost::any(vec.begin());
else
return boost::any(vec.rbegin());
}
int main()
{
std::vector<int> myvec;
myvec.push_back(1);
myvec.push_back(2);
myvec.push_back(3);
typedef std::vector<int>::iterator vecIter;
typedef std::vector<int>::reverse_iterator vecRIter;
try
{
boost::any iter = getIterator(myvec, false);
boost::any iter2 = getIterator(myvec, true);
vecIter it1 = any_cast<vecIter>(iter);
vecRIter it2 = any_cast<vecRIter>(iter2);
MSG(*it1);//output 1
MSG(*it2);//output 3
return true;
}
catch(const boost::bad_any_cast &)
{
return false;
}
}
Use boost::variant or boost::any.
boost::variant< reverse_iterator, iterator >
generate_iterator(...) {
if(...) return iterator();
else return reverse_iterator();
}
// user code
boost::variant< reverse_iterator, iterator > v = generate_iterator();
if(reverse_iterator* it = boost::get<reverse_iterator>(v))
...;
else if(...)
...;
Although the variant is better accessed through a visitor.
The downside is that you need some boiler plate to extract the proper type and is exactly the reason why something like any_iterator might be a more sensible choice.
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.