Reputation: 25613
I found a lot of answers here to the topic, but I couldn't get my code to run.
EDIT: The posted example now works after introducing the missing things. In hope some one can use the example as basis for own experiments. I also introduced the missing things to use this example as random access iterator. It works much more efficient with binary_search algos.
If I have to write my own iterator I struggle with value_type and other "specials" to operate with .
I read a lot of articles here how to NOT write iterators but could not get any working example. Especially I read that I should not derive from iterator. So I will ask stupid again:
How can I define the value_type of my iterator. It did not work with in class definition and also did not work with defining manually over type_traits struct. No idea how to continue...
#include <iostream>
#include <algorithm>
#include <type_traits>
#include <iterator>
using namespace std;
int data[]= { 1,4,7,9,11,20,28 }; //Sorted data
template < typename T >
class MyIter
{
int offset;
T* base;
public:
typedef int value_type;
//add the following lines after reading the answers -> it works!
typedef std::ptrdiff_t difference_type;
typedef T * pointer;
typedef T & reference;
typedef std::forward_iterator_tag iterator_category;
// if you want to use as random access iterator:
// typedef std::random_access_iterator_tag iterator_category;
public:
MyIter( T* _base, int _offset) : base(_base), offset(_offset) {}
MyIter() {}
bool operator !=( const MyIter& rhs)
{
T* tmp1= base+offset;
T* tmp2= rhs.base + rhs.offset;
return tmp1 != tmp2;
}
MyIter operator++(int)
{
MyIter tmp(*this);
offset++;
return tmp;
}
T operator*()
{
return *(base+offset);
}
// Addition: if used as random access iterator you must provide:
int operator-(const MyIter& rhs)
{
return offset-rhs.offset;
}
MyIter operator+=(int off)
{
offset+=off;
return *this;
}
};
typedef MyIter<int> iterType ;
int main()
{
cout << "ok" << endl;
pair<iterType, iterType> bounds;
MyIter<int> start( data,0);
MyIter<int> ende ( data,7);
bounds = equal_range( start, ende, 28 );
for ( iterType it= bounds.first; it!=bounds.second; it++)
{
cout << "Found " << *it << endl;
}
return 0;
}
Upvotes: 2
Views: 511
Reputation: 70526
You are missing several essential type members and the pre-increment operator (as well as a bunch of other dereference and comparison operators as pointed out by @MikeSeymour). Add thise to your class definition (note that I rewrote the post-increment operators in terms of the currently missing pre-increment operator) to get your binary_search
going
typedef std::forward_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
MyIter& operator++()
{
++offset;
return *this;
}
MyIter operator++(int)
{
MyIter tmp(*this);
++*this; // NOTE this will call the other operator++
return tmp;
}
Output on LiveWorkSpace As pointed out by @JamesKanze, these missing typedefs are provided by inheriting from std::iterator<std::forward_iterator_tag, T>
.
Upvotes: 1
Reputation: 254471
You are missing a few definitions in addition to value_type
that the standard library requires from iterators:
typedef std::ptrdiff_t difference_type;
typedef T * pointer;
typedef T & reference;
typedef std::forward_iterator_tag iterator_category;
Alternatively, inheriting from std::iterator<std::forward_iterator_tag, T>
will give you these. I don't know where you read that you shouldn't do that, but that's exactly what std::iterator
is for.
Additionally, you're missing a pre-increment operator:
MyIter operator++()
{
++offset;
return *this;
}
and also ->
and ==
operators. Also, the dereference operator should probably return a reference to allow *it = 42
, with a const
overload returning a value or const
reference.
Upvotes: 3
Reputation: 153929
std::binary_search
requires a random access iterator. Which
means that the iterator must support addition and subtraction
(+
, +=
, -
and -=
), with exactly the same semantics as
a pointer. And any number of algorithms will also expect
a number of typedef in the iterator: deriving from
std::iterator
is the easiest way to get them. (Technically,
what the standard requires is that std::iterator_traits
yield
the correct values, so you could explicitly instantiate it for
your iterator. But its default implementation picks up typedef
in the iterator class.)
Rereading your post: you definitly should publically derive from std::iterator
. Whoever says otherwise is wrong.
Upvotes: 1