I'm actually new to c++. I mostly worked with Java.
I tried to build my own iterator, and after a bit of reading, came up with this method.
template<class T> class Iterable
{
T start,stop;
public:
explicit Iterable(T s,T e) {start=s; stop=e;}
public:
virtual void next(T& i);
public:
class iterator: public std::iterator<
std::input_iterator_tag, // iterator_category
T, // value_type
long, // difference_type
const T*, // pointer
T // reference
>{
T current;
Iterable<T>& obj;
public:
explicit iterator(T t,Iterable<T>& o) : obj(o) {current=t;}
iterator& operator++() {obj.next(current); return *this;}
iterator operator++(int) {iterator retval = *this; ++(*this); return retval;}
bool operator==(iterator other) const {return current == other.current;}
bool operator!=(iterator other) const {return !(*this == other);}
T operator*() const {return current;}
};
iterator begin() {return iterator(start,*this);}
iterator end() {return iterator(stop,*this);}
};
class Range : public Iterable<long>
{
long START,STOP;
public:
void next(long& cur) override
{
if(START>=STOP)
cur++;
else
cur--;
}
public:
Range(long st,long en) : Iterable(st,en) {START=st; STOP=en;}
};
This is my "flex.h" header file. The header compiles OK.
However, when I try to use this Range class, I get the error:
undefined reference to `flex::Iterable<long>::next(long&)'
collect2: error: ld returned 1 exit status
in my compiler (I use g++)
My Test1.cpp file is as follows:
(After includes)
int main()
{
Range range=Range(15,10);
for(auto r : range)
cout << r << "\n";
}
Could someone explain where I went wrong, and how this can be fixed?
Thanks.
You declare a virtual function in next, and don't define it.
A virtual member function has to be defined, be pure virtual, or both. So if you declare
virtual void next(T& i);
It must be defined either inline or outside the class definition because it is not pure virtual. If you intended to make Iterable a template for abstract classes, then adding the pure virtual specifier to next will absolve the error.
virtual void next(T& i) = 0;
Related
Below I depict the general structure of my code:
class OperandIterator : public std::iterator<std::input_iterator_tag, pOpReference>
{
public:
OperandIterator(...)...
OperandIterator & operator++(); // also calls to advance()
OperandIterator operator++(int); // also calls to advance()
bool operator==(const OperandIterator & other) const;
bool operator!=(const OperandIterator & other) const;
pOpReference operator*();
protected:
virtual void advance();
}
class OperandSpecialIterator : public OperandIterator
{
public:
...
private:
void advance() override; // this is the only diffrence between the classes
}
class TraversalPattern
{
public:
TraversalPattern(Operand op, Order order, bool specialTraversal);
OperandIterator begin() { return specialTraversal ? OperandSpecialIterator(...) : OperanInerator(...); }
}
// somewhere
TraversalPattern p(...specialTraversal=ture);
OperandIterator iter = p.begin();
it++;
Even though begin() function returns OperandSpecialIterator, when it++ performed the advance function that is being called is the advance function of OperandIterator.
The problem is that begin() can't return a reference.
The question is:
Can begin function return iterators of different types?
What you are asking is not possible. The begin() function cannot return different types depending on a runtime value. What you could do, is implement something like a VariantIterator that can hold different types of operators in an std::variant (C++17) and forwards the iterator operations to the currently held iterator.
For this simple case, I personally would do the advancing by passing a function pointer to my Iterator:
class OperandIterator; // forward declaration
namespace advancers { // Forward declarations since definition only works,
// when OperandIterator is defined. You can make this easier by making
// these methods static in the class. I declare them forward to be able
// to use them as defaults in OperandIterator.
void advance_normally(OperandIterator& it);
void advance_specially(OperandIterator &it);
} // End namespace advancers
class OperandIterator : public std::iterator<std::input_iterator_tag, pOpReference>
{
public:
OperandIterator() = default;
OperandIterator(void (*advanc_fnc)(OperandIterator&)) : advancer(advanc_fnc) {}
OperandIterator & operator++(); // also calls advancer with *this
OperandIterator operator++(int); // also calls advancer with *this
private:
const void (*advancer)(OperandIterator&) = &advancers::advance_normally;
}
namespace advancers { // Definitions
void advance_normally(OperandIterator& it) {
it++;
}
void advance_specially(OperandIterator &it) {
// Something else
}
} // End namespace advancers
OperandIterator make_special() {
return OperandIterator(&advancers::advance_specially);
}
class TraversalPattern
{
public:
TraversalPattern(Operand op, Order order, bool specialTraversal);
OperandIterator begin() { return specialTraversal ? OperandSpecialIterator() : make_special(); }
}
// somewhere
TraversalPattern p(...specialTraversal=ture);
OperandIterator iter = p.begin();
it++;
The nice thing about this is, that you can easily add more versions of advancing and even make them in place with a lambda.
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 am currently creating a set of iterators which will differ in implementation detail, but will be used in the same algorithms. For this reason, they must all have the same interface. To achieve this, I created an abstract iterator class and inherited from this class in all further iterators.
This should give you an idea of what my code looks like:
class INodeIterator
{
public:
virtual ~INodeIterator() {};
virtual bool operator!= (const INodeIterator& other) =0;
virtual bool operator== (const INodeIterator& other) =0;
virtual INodeIterator& operator++ () =0;
virtual INodeIterator& operator++ (int i) =0;
virtual Node& operator* () =0;
};
class NodeIterator : public INodeIterator
{
public:
/* snip */
NodeIterator& operator++ (int i)
{
NodeIterator tmp(*this);
++(*this);
return(tmp);
}
};
Now I am facing the same problem as in C++ post-increment operator overload in iterators (compiling with -Wall -Werror): My operator++(int) implementation throws a warning (gcc 4.8.0) that a reference to a temporary is returned. The solution in the linked question was to just return the object instead of the reference.
However, this will not work for me. If I change both interface and derived class to return an object instead of a reference, the following errors appear (excerpt, additional file names etc. removed):
INodeIterator.h:16:27: error: invalid abstract return type for member function ‘virtual INodeIterator INodeIterator::operator++(int)’
virtual INodeIterator operator++ (int i) =0;
^
NodeIterator.h:33:22: error: invalid covariant return type for ‘virtual NodeIterator NodeIterator::operator++(int)’
NodeIterator operator++ (int i);
^
INodeIterator.h:16:27: error: overriding ‘virtual INodeIterator INodeIterator::operator++(int)’
virtual INodeIterator operator++ (int i) =0;
^
Changing the return type to object on the derived class but not on the abstract class expectedly returns a "conflicting return type specified" error.
How can I make this work?
Try to change design: let's NodeIterator holds INodeIterator as a pointer. All methods of NoteIterator will delegates to the holding INodeIterator object. In that case you can use correct signature:
struct IteratorInterface {
virtual ~IteratorInterface() {}
virtual std::unique_ptr<IteratorInterface> clone() const = 0;
virtual void next() = 0;
};
class Iterator {
std::unique_ptr<IteratorInterface> impl;
public:
Iterator(std::unique_ptr<IteratorInterface> r) : impl(std::move(r)) {}
Iterator(const Iterator &r) : impl(r.impl->clone()) {}
Iterator& operator++() {
impl->next();
return *this;
}
Iterator operator++(int ) {
Iterator tmp(*this);
impl->next();
return tmp;
}
void swap(Iterator &other) {
other.impl.swap(impl);
}
};
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
struct IteratorInterfaceImpl : IteratorInterface {
int i;
IteratorInterfaceImpl() : i(0) {}
virtual std::unique_ptr<IteratorInterface> clone() const {
return std::unique_ptr<IteratorInterface>(new IteratorInterfaceImpl(*this));
}
virtual void next() {
i += 1;
}
};
Iterator tmp(std::unique_ptr<IteratorInterface>(new IteratorInterfaceImpl()));
tmp++;
++tmp;
return 0;
}
The only sane way I can think of is to return void from INodeIterator::operator++(int) - i.e. nothing.
You can't return a reference from the post-increment operator, because you'll have to create an actual object (storing the previous value) of which you return a reference. This object is either dynamically allocated and would have to be destroyed (had to call delete explicitly on the reference returned) or it is a "local variable" of operator++(int) and will get destroyed before returning:
virtual NodeIterator& operator++(int)
{
NodeIterator prev_value(*this);
++(*this);
return prev_value; // dangling/invalid reference, `prev_value` is destroyed
}
virtual NodeIterator& operator++(int)
{
NodeIterator* pPrev_value = new NodeIterator(*this);
++(*this);
return *pPrev_value; // have to explicitly call delete on the returned ref...
}
You also cannot return an object of type INodeIterator from INodeIterator::operator++(int) because it's an abstract class.
The reason you get the error
INodeIterator.h:16:27: error: invalid abstract return type for member function ‘virtual INodeIterator INodeIterator::operator++(int)’
virtual INodeIterator operator++ (int i) =0;
Is because your pure virtual function returns a abstract class object.
One solution is to use new operator and return the object created in heap, which is safe.
virtual INodeIterator& operator++ (int i) =0;
NodeIterator& operator++ (int i)
{
NodeIterator* tmp = new NodeIterator (*this);
++(*this);
return(*tmp);
}
Your prototype is incorrect. It should be
NodeIterator operator++ (int i)
That is, drop the reference return, otherwise you are returning a reference to something that has gone out of scope (your tmp) Not a good idea!
And the compiler was being very helpful in letting you know this!
Not quite what you wanted to hear I know.
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.
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?