2010-07-06 11 views
7

Estoy tratando de convertir una clase de iterador Tengo que ser stl compatible para que pueda ser utilizado con los algoritmos STL. En el siguiente ejemplo sencillo (y francamente inútil), que debe imprimir los valores de 0 a 5 inclusive, que estoy consiguiendo los errores siguientes,Escribiendo stl compatible con iteradores

ISO C++ prohíbe incrementar un puntero del tipo 'iterador (*)()'

y,

conversión

no válido de 'iterador (*)()' a 'int'

¿Qué estoy haciendo mal?

Gracias.


#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); 
} 
+0

¿Está utilizando esto para una clase de contenedor personalizado? – Alerty

Respuesta

10

Usted está de paso las funciones begin y end a std::for_each, en lugar de los iteradores que estas funciones volverían:

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

que debe ser:

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

también tenga en cuenta que elvacío Las declaraciones, como en if(val==-1 || val==6) throw;, no harán nada bueno. Usted tiene para tirar algo, como throw std::out_of_range("out of bounds").

+0

Podría usar 'throw()' si quiere obligar a la función a que no arroje nada. Por ejemplo, no querría que un destructor de clase arrojara nada. Entonces tiene una precaución que se puede usar 'throw()'. – Alerty

+0

Oh gawd. ¿Cómo no lo vi? La falta de sueño tal vez (prometo no hacer más preguntas hasta que haya tenido alguna!). Muchas gracias. Me siento un poco tonto ahora. – tjm

+0

@Antony: Pero las funciones quieren lanzar cuando el índice está fuera de límites, por lo que una especificación de excepción 'throw()' no está ayudando. Además, 'throw()' no implica ninguna comprobación de tiempo de compilación, sino que terminará el programa si la función pasa a lanzar de todos modos. – sth

8

En primer lugar, usted debe estar pasando los iteradores que son devueltos por begin() y al final() no las propias funciones:

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

En segundo lugar, sería útil tener una clase de iterador con plantilla:

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; 
}; 

En tercer lugar, es posible que realmente no desee tener una clase de iterador así. Aquí está un ejemplo de lo que puede hacer (tenga en cuenta una clase de iterador es un poco más baja):

#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; 
} 
+0

Gracias. Sí, en el mundo real tengo mi iterador como clase interna de un contenedor con plantilla. Mi publicación fue solo un ejemplo de trabajo mínimo que reprodujo los errores que pude ver en mi ejemplo del mundo real. ¡No solo quería un iterador que iterara sobre 0-> 5! Pero gracias por tu respuesta. – tjm

Cuestiones relacionadas