senseiwa
senseiwa

Reputation: 2499

Simple iterator: error with std::count

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

Answers (2)

James Kanze
James Kanze

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

mfontanini
mfontanini

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 typedefs 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 typedefs, but there is no reason to define them manually, std::iterator already does that.

Demo here.

Upvotes: 5

Related Questions