Have a quick question about what would be the best way to implement iterators in the following:
Say I have a templated base class 'List' and two subclasses "ListImpl1" and "ListImpl2". The basic requirement of the base class is to be iterable i.e. I can do:
for(List<T>::iterator it = list->begin(); it != list->end(); it++){
...
}
I also want to allow iterator addition e.g.:
for(List<T>::iterator it = list->begin()+5; it != list->end(); it++){
...
}
So the problem is that the implementation of the iterator for ListImpl1 will be different to that for ListImpl2. I got around this by using a wrapper ListIterator containing a pointer to a ListIteratorImpl with subclasses ListIteratorImpl2 and ListIteratorImpl2, but it's all getting pretty messy, especially when you need to implement operator+ in the ListIterator.
Any thoughts on a better design to get around these issues?
If you can get away with making List<T>::iterator non-virtual, then delegating the virtualness off add to List makes things simple:
template<typename T>
class List
{
virtual void add_assign(iterator& left, int right) = 0;
public:
class iterator
{
const List* list;
const T* item;
public:
iterator(const List* list, const T* item) : list(list), item(item) {}
iterator& operator +=(int right)
{
list->add_assign(*this, right);
return *this;
}
static iterator operator +(iterator const& left, int right)
{
iterator result = left;
result += right;
return result;
}
};
virtual iterator begin() const = 0;
virtual iterator end() const = 0;
};
Otherwise (if the iterators need to store significantly different data, for example), then you have to do the regular, boring pointer-to-implementation to get your virtualness:
template<typename T>
class List
{
class ItImpl
{
virtual ItImpl* clone() = 0;
virtual void increment() = 0;
virtual void add(int right) = 0;
};
public:
class iterator
{
ItImpl* impl;
public:
// Boring memory management stuff.
iterator() : impl() {}
iterator(ItImpl* impl) : impl(impl) {}
iterator(iterator const& right) : impl(right.impl->clone()) {}
~iterator() { delete impl; }
iterator& operator=(iterator const& right)
{
delete impl;
impl = right.impl->clone();
return *this;
}
// forward operators to virtual calls through impl.
iterator& operator+=(int right)
{
impl->add(right);
return *this;
}
iterator& operator++()
{
impl->increment();
return *this;
}
};
};
template<typename T>
static List<T>::iterator operator+(List<T>::iterator const& left, int right)
{
List<T>::iterator result = left;
result += right;
return result;
}
template<typename T>
class MagicList : public List<T>
{
class MagicItImpl : public ItImpl
{
const MagicList* list;
const magic* the_magic;
// implement ...
};
public:
iterator begin() const { return iterator(new MagicItImpl(this, begin_magic)); }
iterator end() const { return iterator(new MagicItImpl(this, end_magic)); }
};
There is something very important among iterators, called Iterator Category:
InputIterator
OutputIterator
ForwardIterator
BidirectionalIterator
RandomAccessIterator
Each category define an exact set of operations that are supported, efficiently, by the iterator.
Here, it seems you wish to turn down that powerful identification mechanism to create some kind of bastard category in which the operations are all present, but no guarantee is made on their efficiency.
I think your design smells.
So the problem is that the
implementation of the iterator for
ListImpl1 will be different to that
for ListImpl2. I got around this by
using a wrapper ListIterator
containing a pointer to a
ListIteratorImpl with subclasses
ListIteratorImpl2 and
ListIteratorImpl2, but it's all
getting pretty messy, especially when
you need to implement operator+ in the
ListIterator.
This design is fine IMHO, I can't see anything messy about it. Except for equality and subtraction, operations of the iterator can be implemented by virtual function pretty easily, so you'll have something like
class ListIteratorInterface // abstract
{
protected:
virtual Data& operator*()=0;
// and other operations
};
class ListIteratorA;
class ListIteratorB; // implementation of the above
class ListIterator
{
ListIteratorInterface* impl_;
public:
// when you create this, allocate impl_ on the heap
// operations, forward anything to impl_
};
You could store operator+ as a private virtual method in the base class, and have the iterator call that.
Alternatively, you could consider statically polymorphic list classes, rather than runtime polymorphism.
Say I have a templated base class 'List' and two subclasses "ListImpl1" and "ListImpl2"
What exactly do you gain by using inheritance here?
Related
I am recently trying to know how ranged-for work,
and finally got a picture as below:
for(obj& temp_ref:range r)//hide iterator somewhere as the range defined.
For each iteration,there is just a update of current object to doing the job in one circle of loop,and this is decent explain for me.
But when I trying to combine range and iterator into a mixed class,
there`s a problem of which operator++ should it call in my code,
in the sense, it should be the derivative class method be call in range-based-for,
because I create the object as derivative object,my declare is virtual.
the code is provided here,the first part is sprated and fine,
but the second one is works weird for me.
#include <iostream>
namespace first
{
template<class iterator>
class range
{
public:
range(iterator ina,iterator inb):a(ina),b(inb){};
iterator a,b;
iterator& begin(){return a;};
iterator& end(){return b;};
};
template<class T>
class iterator
{
public:
iterator(T* ini):i(ini){};
T* i;
virtual iterator<T>& operator= (const iterator<T>& other){this->i=other.i;return *this;};
virtual T& operator* (){return *i;};
virtual T operator!= (const iterator<T>& other){return this->i==other.i?0:1;};
virtual void operator++ (){i++;};
};
class jump2:public iterator<int>
{
public:
jump2(int* ini):iterator<int>(ini){};
virtual void operator++ (){i+=2;};
};
}
namespace second
{
template<class T>
class iterator
{
public:
iterator(T* inStart,T* inFinal):current(inStart),final(inFinal){};
T* current;
T* final;
iterator<T> begin(){return iterator<T>(this->current,this->final);};
iterator<T> end(){return iterator<T>(this->final,this->final);};
virtual iterator<T>& operator= (const iterator<T>& other){this->current=other.current;this->final=other.final;return *this;};
virtual T& operator* (){return *this->current;};
virtual bool operator!= (iterator<T>& other){return this->current!=other.final;};
virtual void operator++ ()
{
std::cout<<"<call base>";
this->current=this->current+1;
};
};
template<class T>
class jumper:public iterator<T>
{
public:
jumper(T* inStart,T* inFinal):iterator<T>(inStart,inFinal){};
void operator++ ()
{
std::cout<<"<call deri>";
this->current=this->current+2;
};
};
};
int main()
{
int a[6]={1,0,2,0,3,0};
//success
{
using namespace first;
range<jump2> a_range(jump2(a),jump2(a+6));
for(int store:a_range)
std::cout<<store<<std::endl;
}//pause();
//Fail
{
using namespace second;
jumper<int> a_iterator_call_jumper(a,a+6);
for(int& i:a_iterator_call_jumper)
std::cout<<i<<std::endl;
}//pause();
return 0;
};
this output is
1
2
3
1
<call base>0
<call base>2
<call base>0
<call base>3
<call base>0
<call base>
but it should be like
1
2
3
1
<call deri>2
<call deri>3
<call deri>
Is this thing goes wrong because I use it wrong?
Or there`s a bug I am not find yet?
template<class iterator>
class range
{
public:
range(iterator ina,iterator inb):a(ina),b(inb){};
iterator a,b;
iterator& begin(){return a;};
iterator& end(){return b;};
};
no
template<class iterator>
class range
{
public:
range(iterator ina,iterator inb):a(ina),b(inb){};
iterator a,b;
iterator begin() const {return a;};
iterator end() const {return b;};
};
yes.
template<class T>
class iterator
{
public:
iterator(T* ini):i(ini){};
T* i;
virtual iterator<T>& operator= (const iterator<T>& other){this->i=other.i;return *this;};
virtual T& operator* (){return *i;};
virtual T operator!= (const iterator<T>& other){return this->i==other.i?0:1;};
virtual void operator++ (){i++;};
};
no
template<class T>
class iterator
{
public:
iterator(T* ini):i(ini){};
T* i;
iterator( iterator const& ) = default;
iterator& operator= (const iterator<T>& other) & = default;
T& operator*() {return *i;};
bool operator!= (const iterator& other) const {return this->i==other.i?0:1;};
void operator++() {++i;};
};
yes.
Don't use the standard C++ vtable-based polymorphic object model for iterators; they should be regular types, and the vtable-based polymorphic object model is not regular.
As for second, it is not a good plan. An iterator and the range over which you iterate are not the same thing. Smashing them together makes your class incoherent.
C++ iteration is not designed for dynamic dispatch (polymorphism). You can do it, but it kills performance, and it isn't trivial to write. You basically need to hide the virtual dispatch behind a regular type (and you can dispatch using vtables, or you can dispatch using C++'s void pointer based type erasure).
If you are used to other languages, many other languages descended from C++ use mandatory reference semantics with garbage collection for objects of class type. Their virtual inheritance object model works on reference variables, as it does in C++ with reference and pointer types.
C++ is relatively quirky (in this day and age) in that it supports complex objects as value types, and that the language and standard library presumed you are working with value types most of the time. (Note that a pointer is a kind of value type; but its value is the pointer, not the object), and that when you want to use reference/pointer semantics you have to adapt your code.
I have a pure virtual interface to a container which is more or less like this:
class IContainer
{
public:
virtual ~IContainer() = default;
virtual Element& operator[](size_t index) = 0;
virtual const Element& operator[](size_t index) const = 0;
virtual size_t size() const = 0;
};
I would like to make use of range for loops, so I need to define begin() and end(). In order to do so, I need to define the iterator type as well.
It should be not be particularly hard, but nevertheless I would like to know if is there already anything in STL or Boost that can come to help, before I start coding something that already exists.
It might not be a good idea, but adding for(:) loop support is relatively easy here. I'll be minimal.
I'll create an iteroid, a not-iterator that is enough to support for(:) loops. This requires ++, != and unary * support, and nothing else.
template<class C>
struct index_iteroid {
decltype(auto) operator*()const {
return (*container)[i];
}
index_iteroid(index_iteroid const&)=default;
index_iteroid& operator=(index_iteroid const&)=default;
friend bool operator==(index_iteroid const& lhs, index_iteroid const& rhs) {
return std::tie(lhs.i, lhs.container)==std::tie(rhs.i, rhs.container);
}
friend bool operator!=(index_iteroid const& lhs, index_iteroid const& rhs) {
return !(lhs==rhs);
}
void operator++()&{
++i;
}
index_iteroid(C* c, std::size_t in):i(in), container(c) {}
private:
std::size_t i = 0;
C* container = nullptr;
};
now we use it:
class IContainer
{
public:
virtual ~IContainer() = default;
virtual Element& operator[](size_t index) = 0;
virtual const Element& operator[](size_t index) const = 0;
virtual size_t size() const = 0;
index_iteroid<IContainer> begin() { return {this, 0}; }
index_iteroid<IContainer> end() { return {this, size()}; }
index_iteroid<IContainer const> begin() const { return {this, 0}; }
index_iteroid<IContainer const> end() const { return {this, size()}; }
};
and there you have it.
void test( IContainer* cont ) {
if (!cont) return;
for(Element& e : *cont) {
// code
}
}
please excuse any typos.
Now a full iterator takes about 2-3 times as much code as my iteroid does, but nothing tricky, just annoying boilerplate mostly.
The standard doesn't have much to help you. For boost, you could compose a counting iterator with a function caling iterator/generator, and have the function call use []. Boost also has some utilities to make it take less boilerplate to write a full iterator, if you want to upgrade the iteroid to an iterator.
C++ doesn't do "interfaces" like this. The idiomatic way is for the (potential) clients of IContainer to instead be templated over the container type and just call values[index], or be templated over an iterator type and call like *(first + offset).
In C++20 you will be able to write a Container Concept, which behaves somewhat like an interface definition, but you can already express a Concept as documented requirements.
If instead you want a type-erased random access "container", you can use boost::any_range<Element, boost::random_access_traversal_tag>
I want to know how to have a c++ class to be iterable (stl compatible) without exposing the implementation ?
The structure of the project is like :
Stream
class Stream
{
public:
Stream();
[...]
StreamIterator iter()
{
return StreamIterator(this);
}
private:
class impl;
std::unique_ptr<impl> pimpl;
};
StreamFilter
class StreamFilter
{
public:
StreamFilter();
[...]
private:
class impl;
std::shared_ptr<impl> pimpl;
};
StreamIterator
class StreamIterator
{
public:
StreamIterator(Stream* streamToFilter);
[...]
void addFilter(StreamFilter* filter);
void removeFilter(StreamFilter* filter);
[...]
private:
class impl;
std::unique_ptr<impl> pimpl;
};
StreamFilter is a base class for differents filtering strategies.
For simplicity in the sample code, I used raw memory pointers, of course in a real exploitation code I use intelligents pointers : shared, weak ...
I want to allow the StreamIterator become iterable in a STL way, doing :
StreamIterator iter = stream.iter();
iter.addFilter(new FilterByOffset([...with parameters...]));
for (auto item : iter)
{
[...doing something with filtered items...]
}
The basic way is to add some accessors to allow range-based for loop.
StreamIterator
class StreamIterator
{
public:
StreamIterator(Stream* streamToFilter);
[...]
iterator begin();
iterator end();
const_iterator cbegin() const;
const_iterator cend() const;
[...]
void addFilter(StreamFilter* filter);
void removeFilter(StreamFilter* filter);
[...]
private:
class impl;
std::unique_ptr<impl> pimpl;
};
Where iterator and const_iterator are basically typedef's to the internal container iterators. And this is the problem.
First, I don't want to expose private implementation in the StreamIterator header. And so, iterator and const_iterator are not allowed here.
Second, because of the stream filtering strategy, the iterators returned are not just alias to some internal stl containers. In the internal implementation, I need to call the filters in a functor way to check if the item need to be exclude or not.
The only type allowed in the StreamIterator header is the type of the item object returned.
Is there a way to do that?
Thank you very much!
Additional Information:
Maybe this declaration is a way to allow a private implementation, I need to investigate more :
StreamIterator
class StreamIterator
{
public:
StreamIterator(Stream* streamToFilter);
[...]
struct iterator
{
Object::Ptr operator*();
iterator& operator++();
bool operator!= (const iterator& it) const;
};
typedef typename StreamIterator::iterator iterator;
iterator begin();
iterator end();
[...]
void addFilter(StreamFilter* filter);
void removeFilter(StreamFilter* filter);
[...]
private:
class impl;
std::unique_ptr<impl> pimpl;
};
First, don't call it StreamIterator; an iterator is a pointer-like object for which 2 of them can specify a range. Your StreamIterator doesn't have this. Nothing good can come of reusing the well defined iterator term here.
Now, your StreamIterator is some kind of range of iterators. So we'll call it a StreamRange.
In order to hide how StreamRange can be iterated over, you have to hide how the iterators it uses work.
And this -- hiding the implementation detalis of a stream iterator -- has a substantial cost to it.
When iterating over a loop, each step in the loop involves ++ and * and an ==. Throwing a pointer indirection and a vtable lookup (or equivalent) on each of those will make your loops much slower.
But here is how to do it.
template<class Value>
struct any_input_iterator {
using difference_type = std::ptrdiff_t;
using value_type=Value;
using pointer = value_type*;
using reference = value_type;
using iterator_category = std::input_iterator_tag;
private:
struct vtable_t {
bool(*equal)( std::any const& lhs, std::any const& rhs ) = 0;
Value(*get)( std::any& ) = 0;
void(*inc)( std::any& ) = 0;
};
vtable_t const* vtable = 0;
std::any state;
template<class U>
static vtable_t make_vtable() {
return {
[](std::any const& lhs, std::any const& rhs)->bool {
return std::any_cast<U const&>(lhs) == std::any_cast<U const&>(rhs);
},
[](std::any& src)->Value {
return *std::any_cast<U&>(src);
},
[](std::any& src) {
++std::any_cast<U&>(src);
}
};
}
template<class U>
static vtable_t const* get_vtable() {
static const auto vtable = make_vtable<U>();
return &vtable;
}
public:
template<class U,
std::enable_if_t<!std::is_same<std::decay_t<U>, any_input_iterator>{}, bool> = true
>
any_input_iterator(U&& u):
vtable(get_vtable<std::decay_t<U>>()),
state(std::forward<U>(u))
{}
any_input_iterator& operator++() { vtable->inc(state); return *this; }
any_input_iterator operator++(int) { auto tmp = *this; ++*this; return tmp; }
reference operator*() { return vtable->get(state); }
friend bool operator==( any_input_iterator const& lhs, any_input_iterator const& rhs ) {
if (lhs.vtable != rhs.vtable) return false;
if (!lhs.vtable) return true;
return lhs.vtable->equal( lhs.state, rhs.state );
}
friend bool operator!=( any_input_iterator const& lhs, any_input_iterator const& rhs ) {
return !(lhs==rhs);
}
struct fake_ptr {
Value t;
Value* operator->()&&{ return std::addressof(t); }
};
fake_ptr operator->()const { return {**this}; }
};
there are probably some typoes, but this is basic type erasure. Boost does a better job at this.
I only supported input iterators. If you want to support forward iterators, you have to change up some typedefs and return references and the like.
any_input_iterator<int> begin();
any_input_iterator<int> end();
that is, however, enough to let someone iterate over your range in question.
It will be slow, but it will work.
My requirements are same to the question asked Using Iterators to hide internal container and achieve generic operation over a base container[1] at stackoverflow. I have a generic pure virtual base container class, which needs to provide an iterator which should be STL complaint so I can use them with cpp algorithm's #include <algorithm>. My implementation uses only an single class instead of two classes as in [1] solution.
Base pure virtual class
class BaseItr
{
public:
class iterator : public std::iterator<std::input_iterator_tag, int>
{
public:
iterator() : _in(NULL) {}
inline iterator(const iterator& org) : _in(org._in) {}
inline iterator& operator=(const iterator& other) { _in = other._in; return *this; }
virtual inline int operator * () { return _in->operator*(); }
virtual inline iterator& operator++() { (*_in)++; return *this; }
virtual inline iterator& operator++(int unused) { (*_in)++; return *this; }
virtual inline bool operator==(const iterator& other)
{
return *(*_in) == *(*(other._in));
}
virtual inline bool operator!=(const iterator& other)
{
return *(*_in) != *(*(other._in));
}
// would use shared pointer insted of this
//~iterator() { if(_in) { delete _in; } }
static inline iterator New(iterator *in) { return iterator(in); }
private:
iterator(iterator *in) : _in(in) {}
iterator *_in;
};
virtual iterator begin() = 0;
virtual iterator end() = 0;
};
Implementation
class Itr : public BaseItr
{
private:
class iterator : public BaseItr::iterator
{
public:
iterator(int val) : _val(val), BaseItr::iterator() {}
int operator * () { return _val; }
inline iterator& operator++() { ++_val; return *this; }
inline iterator& operator++(int unused) { _val++; return *this; }
private:
int _val;
};
BaseItr::iterator _begin;
BaseItr::iterator _end;
public:
inline Itr(int start, int end)
{
_begin = BaseItr::iterator::New(new iterator(start));
_end = BaseItr::iterator::New(new iterator(end));
}
BaseItr::iterator begin() { return _begin; }
BaseItr::iterator end() { return _end; }
};
My implementation works was need, I want to know are there any drawbacks with this implementation, Please help me decide with my design to use the appropriate implementation. I have add my full working example code in github:gist https://gist.github.com/3847688
Ref:
Iterator for custom container with derived classes
Using Iterators to hide internal container and achieve generic operation over a base container
Fast and flexible iterator for abstract class
C++ : Using different iterator types in subclasses without breaking the inheritance mechanism
The most glaring issue: your iterator does not have value semantics.
The STL algorithms are free to copy an iterator if they wish. For example suppose:
template <typename It>
It find(It b, It e, typename std::iterator_traits<It>::const_reference t) {
for (; b != e; ++b) {
if (*b == t) { return b; }
}
return e;
}
The problem is that if you invoke this algorithm with BaseItr&, then the result is of type BaseItr, and you are thus exposed to Object Slicing, which is undefined behavior.
In order to give value semantics to you iterator, you need to create a wrapper class around an abstract implementation and have the wrapper correctly manage the copy through a virtual clone method. If your iterator ends up with virtual methods, you are doing it wrong.
I have problems comparing template implementations of the same interface through overriden equality operator.
Interface* ptr1 = ...; Interface* ptr2 = ...;
*ptr1 == *ptr2;
The only solution I've came up to is to enforce that only identically implemented objects are to be compared and to implement comparison like this:
class Interface {
public:
virtual ~Interface() {}
virtual bool operator==(const Interface&) const = 0;
};
template <typename T> class Impl : public Interface {
public:
bool operator==(const Interface& rhs) const {
assert(typeid(rhs) == typeid(const Impl&));
const Impl& rhsRef = static_cast<const Impl&>(rhs);
// ...
}
};
The problem in this solution is that it's too limited for my purposes - I'd want to be able to compare different implementations. If there were a limited number of implementations, it would be possible to use double dispatch pattern. But in my case Impl is a template, so double dispatch is not possible, because it would need a virtual function template:
// This obviously doesn't work.
class Interface {
public:
virtual ~Interface() {}
virtual bool operator==(const Interface&) const = 0;
template <typename T2> virtual bool operator==(const Impl<T2>&) const = 0;
};
template <typename T> class Impl : public Interface {
public:
bool operator==(const Interface& rhs) const {
return rhs == *this;
}
template <typename T2> bool operator==(const Impl<T2>& rhs) const {
// ...
}
};
Is there any solution? I need this to write AnyIterator class, which can wrap any STL iterator. But I can't compare AnyIterators, if they are wrapped around different types, for example iterator and const_iterator:
std::list<int>::iterator it1 = ...; std::list<int>::const_iterator it2 = ...;
AnyIterator<const int> myIter1 = it1; AnyIterator<const int> myIter2 = it2;
it1 == it2; // This works perfectly.
myIter1 == myIter2; // This doesn't work!
I think the problem here is that having operator== in your Interface, just doesn't make any sense at all. If you want to provide comparison for your implementation, that's another matter, like:
bool operator==(const Impl<T>& other) const {
// ...
}
Even for that case, though, I would generally discourage creating operator overloads; instead, provide accessors to get the relevant attributes that someone might want to compare, and leave it up to whoever is using your code to create the comparisons that they want to make.
Do you have a specific use case for these arbitrary comparisons?
You can use dynamic_cast instead of static_cast and check for std::bad_cast (and just always return false in that case). You could use a pointer dynamic_cast instead of a reference cast, in which case you'd just have to check for NULL instead of catching an exception.