Запись stl совместимые итераторы

Я пытаюсь преобразовать класс итератора, я должен быть stl совместимый так, чтобы он мог использоваться с stl алгоритмами. В следующем простом (и откровенно бесполезный) пример, который должен распечатать значения от 0 до 5 содержащих, я получаю следующие ошибки,

ISO C++ запрещает постепенное увеличение указателя типа ‘Итератор (*) ()‘

и,

недопустимое преобразование из ‘Итератора (*) ()’ к 'интервалу'

Что я делаю неправильно?

Спасибо.


#include <iterator>
#include <algorithm>
#include <iostream>

class Iterator : public std::iterator<std::bidirectional_iterator_tag, int> {
    public:
        Iterator(int i = 0) : val(i) {
            if(val<0 || val>5) throw;
        }

        bool operator==(Iterator const& rhs) const {
            return (val==rhs.val);
        }

        bool operator!=(Iterator const& rhs) const {
            return !(*this==rhs);
        }

        Iterator& operator++() {
            if(val!=6)
                ++val;
            return *this;
        }   

        Iterator operator++(int) {
            Iterator tmp (*this);
            ++(*this);
            return tmp;
        }

        Iterator& operator--() {
            if(val!=-1)
                --val;
            return *this;
        }

        Iterator operator--(int) {
            Iterator tmp (*this);
            --(*this);
            return tmp;
        }

        int operator* () const {
            if(val==-1 || val==6) throw;
            return val;
        }

    private:
        int val;
};

Iterator begin() {
    return Iterator();
}

Iterator end() {
    return ++Iterator(5);
}

void print(int i) {
    std::cout << i << std::endl;
}

int main(int argc, char* argv[]) {
    std::for_each(begin,end,print);
}
7
задан tjm 6 July 2010 в 00:28
поделиться

2 ответа

Вы передаете функции begin и end в std::for_each, вместо итераторов, которые эти функции вернут:

std::for_each(begin,end,print);

Должно быть:

std::for_each(begin(),end(),print);

Также обратите внимание, что пустые throw утверждения, как в if(val==-1 || val==6) throw;, не принесут ничего хорошего. Вы должны бросить что-то, например бросить std::out_of_range("out of bounds").

11
ответ дан 6 December 2019 в 09:18
поделиться

Во-первых, вы должны передавать итераторы, которые возвращаются begin () и end (), а не сами функции:

int main(int argc, char* argv[]) 
{
    std::for_each(begin(),end(),print);
}

Во-вторых, было бы полезно иметь шаблонный класс Iterator:

template<class T>
class Iterator : public std::iterator<std::bidirectional_iterator_tag, int>
{
    public:
        typedef T value_type; //notice this here :D

        Iterator(value_type t = 0) : val(t) 
        {
            if(val<0 || val>5) throw; //never hardcode something like that :S
        }

        bool operator==(Iterator const& rhs) const 
        {
            return (val==rhs.val);
        }

        bool operator!=(Iterator const& rhs) const 
        {
            return !(*this==rhs);
        }

        Iterator& operator++() 
        {
            if(val!=6) //never hardcode something like that :S
                ++val;
            return *this;
        }   

        Iterator operator++(value_type) 
        {
            Iterator tmp (*this);
            ++(*this);
            return tmp;
        }

        Iterator& operator--() 
        {
            if(val!=-1) //never hardcode something like that :S
                --val;
            return *this;
        }

        Iterator operator--(value_type) 
        {
            Iterator tmp (*this);
            --(*this);
            return tmp;
        }

        value_type operator* () const 
        {
            if(val==-1 || val==6) throw; //never hardcode something like that :S
            return val;
        }

    private:
        value_type val;
};

В-третьих, вы могли бы на самом деле не хочу иметь такой класс итератора. Вот пример того, что вы можете сделать (обратите внимание, что класс итератора немного ниже):

#include <algorithm>

template<class T>
class List
{
public:
    typedef T value_type;
    typedef std::size_t size_type;

private:
    struct Knot
    {
        value_type val_;
        Knot * next_;
        Knot(const value_type &val)
        :val_(val), next_(0)
        {}
    };
    Knot * head_;
    size_type nelems_;

public:
    //Default constructor
    List() throw()
    :head_(0), nelems_(0)
    {}
    bool empty() const throw()
    { return size() == 0; }
    size_type size() const throw()
    { return nelems_; }

private:
    Knot * last() throw() //could be done better
    {
        if(empty()) return 0;
        Knot *p = head_;
        while (p->next_)
            p = p->next_;
        return p;
    }

public:
    void push_back(const value_type & val)
    {
        Knot *p = last();
        if(!p)
            head_ = new Knot(val);
        else
            p->next_ = new Knot(val);
        ++nelems_;
    }
    void clear() throw()
    {
        while(head_)
        {
            Knot *p = head_->next_;
            delete head_;
            head_ = p;
        }
        nelems_ = 0;
    }
    //Destructor:
    ~List() throw()
    { clear(); }
    //Iterators:
    class iterator
    {
        Knot * cur_;
    public:
        iterator(Knot *p) throw()
        :cur_(p)
        {}
        bool operator==(const iterator & iter)const throw()
        { return cur_ == iter.cur_; }
        bool operator!=(const iterator & iter)const throw()
        { return !(*this == iter); }
        iterator & operator++()
        {
            cur_ = cur_->next_;
            return *this;
        }
        iterator operator++(int)
        {
            iterator temp(*this);
            operator++();
            return temp;
        }
        value_type & operator*()throw()
        { return cur_->val_; }
        value_type operator*() const
        { return cur_->val_; }
        value_type operator->()
        { return cur_->val_; }
        const value_type operator->() const
        { return cur_->val_; }
    };
    iterator begin() throw()
    { return iterator(head_); }
    iterator begin() const throw()
    { return iterator(head_); }
    iterator end() throw()
    { return iterator(0); }
    iterator end() const throw()
    { return iterator(0); }
    //Copy constructor:
    List(const List & lst)
    :head_(0), nelems_(0)
    {
        for(iterator i = lst.begin(); i != lst.end(); ++i)
            push_back(*i);
    }
    void swap(List & lst) throw()
    {
        std::swap(head_, lst.head_);
        std::swap(nelems_, lst.nelems_);
    }
    List & operator=(const List & lst)
    {
        List(lst).swap(*this);
        return *this;
    }
    //Conversion constructor
    template<class U>
    List(const List<U> &lst)
    :head_(0), nelems_(0)
    {
        for(typename List<U>::iterator iter = lst.begin(); iter != lst.end(); ++iter)
            push_back(*iter);
    }
    template<class U>
    List & operator=(const List<U> &lst)
    {
        List(lst).swap(*this);
        return *this;
    }
    //Sequence constructor:
    template<class Iter>
    List(Iter first, Iter last)
    :head_(0), nelems_(0)
    {
        for(;first!=last; ++first)
            push_back(*first);
    }
};

#include <iostream>
using std::cout;
using std::endl;

int main()
{
    const char MAX_LIMIT = 127;
    List<short> listA;
    //...
    List<char> listB = listA; //without the conversion constructor this would not go very far!
    for(char i = 0; i < MAX_LIMIT; ++i)
        listB.push_back(i);
    for(List<char>::iterator iter = listB.begin(); iter != lstB.end(); ++iter)
        cout << *iter << endl;
}
9
ответ дан 6 December 2019 в 09:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: