Reputation: 2499
this is a simple exercise. I'd like to write a custom iterator for a C-style array of characters all by myself: no boost. I think I'm halfway through, but I get an error when using std::count
.
My iterator is this:
class myIterator : std::iterator<std::input_iterator_tag, char>
{
char *p;
public:
// Definitions
typedef typename std::iterator<std::input_iterator_tag, char>::difference_type difference_type;
typedef typename std::iterator<std::input_iterator_tag, char>::value_type value_type;
typedef typename std::iterator<std::input_iterator_tag, char>::reference reference;
typedef typename std::iterator<std::input_iterator_tag, char>::pointer pointer;
// Implementation
myIterator(char* x) :p(x) { };
myIterator(const myIterator& i) : p(i.p) { };
myIterator& operator++() { ++p; return *this; };
myIterator operator++(int) {myIterator tmp(*this); operator++(); return tmp; };
bool operator==(const myIterator& rhs) { return p == rhs.p; };
bool operator!=(const myIterator& rhs) { return p != rhs.p; };
char& operator*() { return *p; };
};
So, when I use the iterator in a for
loop, it's great, it
for (auto it = data.begin(); it != data.end(); it++)
std::cout << *it;
However, this gets a compile-time error:
std::cout << std::count(data.begin(), data.end(), '@') << std::endl;
For what it's worth, data
is a super-simple class with a classic wrapping function for begin()
and end()
(i.e., return myIterator(address_);
and return myIterator(address_ + size_);
).
What's the error is puzzling to me:
error: no matching function for call to 'count'
[...]
note: candidate template ignored: substitution failure [with _InputIterator = myIterator, _Tp = char]: no type named 'difference_type' in 'std::__1::iterator_traits<myIterator>'
count(_InputIterator __first, _InputIterator __last, const _Tp& __value_)
I am missing something here: I declared difference_type
in the iterator.
Can anyone help?
Upvotes: 1
Views: 587
Reputation: 154027
I'm not sure if this is the problem, but the usual way of using
std::iterator
is to inherit publicly from it. Or to not use
it, and define all five of its typedefs. I'd guess the reason
your code doesn't work is that the typedef for iterator_category
isn't accessible: if you don't derive publicly from
std::iterator
, you have to provide it.
For what it's worth, there are three ways of making the
iterator type conform: inherit publicly from std::iterator
,
declare the five typedefs (value_type
, difference_type
,
pointer
, reference
and iterator_category
) directly in your
class (as public), or specialize std::iterator_traits
on your
class (again, with the five typedefs). The first is by far the
simplest and the most usual.
Upvotes: 2
Reputation: 21910
Deriving your class from std::iterator
already defines value_type
, difference_type
, etc. So you shouldn't be defining them. Just make your inheritance public and remove those typedef
s and it will work:
class myIterator : public std::iterator<std::input_iterator_tag, char>
{
char *p;
public:
// Implementation
myIterator(char* x) :p(x) { };
// ......
};
Note that it's not necessary to remove the typedef
s, but there is no reason to define them manually, std::iterator
already does that.
Demo here.
Upvotes: 5