2013-03-01 11 views
5

Sto lavorando su un contenitore che implementa il proprio iteratore, che sto usando con std :: reverse_iterator <> per ottenere la funzionalità di iterazione inversa. Posso assegnare l'iteratore inverso per lacerare o rbegin, ma quando provo ad accedere a qualsiasi delle sue funzionalità (come ad esempio = o ==!) Ottengo questo:Operatore! = È ambiguo per std :: reverse_iterator C++

1 IntelliSense: more than one operator "!=" matches these operands: 
     function template "bool std::operator!=(const std::reverse_iterator<_RanIt1> &_Left, const std::reverse_iterator<_RanIt2> &_Right)" 
     function template "bool avl::operator!=(const tree &left, const tree &right)" 
     operand types are: std::reverse_iterator<avl::avl_iterator<avl::avltree<char, int, std::less<char>, std::allocator<std::pair<const char, int>>>>> != std::reverse_iterator<avl::avl_iterator<avl::avltree<char, int, std::less<char>, std::allocator<std::pair<const char, int>>>>> 

miei iteratore operatore sovraccarichi:

bool operator == (const avl_iterator& rhs) const { return (_node == rhs._node); } 
    bool operator != (const avl_iterator& rhs) const { return (_node != rhs._node); } 

e la mia implementazione di iteratore inverso

typedef typename avl_iterator<tree>        iterator; 
typedef typename const_avl_iterator<tree>       const_iterator; 
typedef typename std::reverse_iterator<iterator>     reverse_iterator; 
typedef typename std::reverse_iterator<const_iterator>    const_reverse_iterator; 

e l'iteratore typedefs:

typedef typename tree::node     node; 
    typedef typename tree::node_ptr    node_ptr; 
    typedef typename tree::value_type*   pointer;// for std reverse iterator 
    typedef typename tree::value_type&   reference; 
    typedef typename tree::const_node_ptr  const_node_ptr; 
    typedef typename tree::utilities   utilities; 
    typedef typename tree::value_type   value_type; 
    typedef std::bidirectional_iterator_tag  iterator_category; 
    typedef std::ptrdiff_t      difference_type; 

Come sto usando l'operatore

avltree<char,int> myTree; 
    myTree.insert(std::pair<char,int>('a',1)); 
    myTree.insert(std::pair<char,int>('b',2)); 
    myTree.insert(std::pair<char,int>('c',3)); 

    avltree<char,int>::reverse_iterator rit = myTree.rbegin(); 

    for(; rit != myTree.rend(); ++rit) //fails on this line 
    { 
    } 

e la classe iteratore (const_iterator è la stessa cosa, ma con un value_type const)

template <class tree> 
class avl_iterator { 
public: 
    typedef typename tree::node     node; 
    typedef typename tree::node_ptr    node_ptr; 
    typedef typename tree::value_type*   pointer;// for std reverse iterator 
    typedef typename tree::value_type&   reference; 
    typedef typename tree::const_node_ptr  const_node_ptr; 
    typedef typename tree::utilities   utilities; 
    typedef typename tree::value_type   value_type; 
    typedef std::bidirectional_iterator_tag  iterator_category; 
    typedef std::ptrdiff_t      difference_type; 

private: 
    friend class const_avl_iterator<tree>; 
    node_ptr _node; 
public: 
    avl_iterator() : _node() { } 
    avl_iterator(const node_ptr node) : _node (node) { } 
    avl_iterator(const avl_iterator& iterator) { 
     (*this) = iterator; 
    } 
    ~avl_iterator() { _node = NULL; } 

    avl_iterator& operator=(const avl_iterator& rhs) { 
     _node = rhs._node; 
     return (*this); 
    } 
    avl_iterator& operator=(const const_avl_iterator<tree>& rhs) { 
     _node = rhs._node; 
     return (*this); 
    } 

    bool operator == (const avl_iterator& rhs) const { return (_node == rhs._node); } 
    bool operator != (const avl_iterator& rhs) const { return (_node != rhs._node); } 

    avl_iterator& operator++() 
    { 
     _node = utilities::next_node(_node); 
     return (*this); 
    } 
    avl_iterator operator ++(int) { 
     avl_iterator temp(*this); 
     ++(*this); 
     return(temp); 
    } 

    avl_iterator& operator --() { 
     _node = utilities::prev_node(_node); 
     return (*this); 
    } 

    avl_iterator operator -- (int) { 
     avl_iterator temp(*this); 
     --(*this); 
     return(temp); 
    } 

    value_type& operator *() const { 
     assert(! utilities::is_header(_node)); 
     return _node->_value; 
    } 

    value_type* operator ->() const { 
     assert(! utilities::is_header(_node)); 
     return &_node->_value; 
    } 
}; 

e la classe albero:

template < 
    class Key, 
    class Type, 
    class Traits = std::less<Key>, 
    class Allocator = std::allocator<std::pair<Key const, Type>> 
    > 
    class avltree { 
    private: 
     typedef avltree< Key, Type, Traits, Allocator>      tree; 
    public: 
     typedef std::pair<const Key, Type>         value_type; 
     typedef Allocator             allocator_type; 
     typedef typename allocator_type::size_type       size_type; 
     typedef typename allocator_type::reference       reference; 
     typedef Key               key_type; 
     typedef Type              mapped_type; 
     typedef Traits              key_compare; 
     typedef typename avl_node<tree>         node; 
     typedef typename node::node_ptr          node_ptr; 
     typedef typename node::const_node_ptr        const_node_ptr; 
     typedef typename avl_utilities<tree>        utilities; 
     typedef typename avl_iterator<tree>        iterator; 
     typedef typename const_avl_iterator<tree>       const_iterator; 
     typedef typename std::reverse_iterator<iterator>     reverse_iterator; 
     typedef typename std::reverse_iterator<const_iterator>    const_reverse_iterator; 
    private: 
     node_ptr _header; 
     std::size_t _size; 
     key_compare _comparer; 
     allocator_type _alloc; 
    public: 
      //c'tors and d'tors 
     //******************************************************* 
     //Iterators 
     //******************************************************* 
     iterator    begin()   { return iterator(node::get_left(_header)); } 
     const_iterator   begin() const { return const_iterator(node::get_left(_header)); } 
     const_iterator   cbegin() const { return const_iterator(node::get_left(_header)); } 
     iterator    end()   { return iterator(_header); } 
     const_iterator   end() const  { return const_iterator(_header); } 
     const_iterator   cend() const { return const_iterator(_header); } 

     reverse_iterator  rbegin()  { return reverse_iterator(_header); } 
     const_reverse_iterator rbegin() const { return const_reverse_iterator(_header); } 
     const_reverse_iterator crbegin() const { return const_reverse_iterator(_header); } 
     reverse_iterator  rend()   { return reverse_iterator(node::get_left(_header)); } 
     const_reverse_iterator rend() const { return const_reverse_iterator(node::get_left(_header)); } 
     const_reverse_iterator crend() const { return const_reverse_iterator(node::get_left(_header)); } 
     bool operator==(const tree& right) 
     { 
      if(_size != right.size()) 
      { 
       return false; 
      } 

      const_iterator lhs = cbegin(); 
      const_iterator rhs = right.cbegin(); 
      while(lhs != cend() && rhs != right.cend()) 
      { 
       if(lhs->first != rhs->first || lhs->second != rhs->second) 
       { 
        return false; 
       } 
       ++lhs; 
       ++rhs; 
      } 
      return true; 
     } 
     bool operator!=(const tree& right) 
     { 
      return (!(*this == right)); 
     } 
     bool operator<(const tree& right) 
     { 
      const_iterator lhs = cbegin(); 
      const_iterator rhs = right.cbegin(); 
      while(lhs != cend() && rhs != right.cend()) 
      { 
       if(lhs->first != rhs->first || lhs->second != rhs->second) 
       { 
        if(lhs->first < rhs->first || lhs->second < rhs->second) 
        { 
         return true; 
        }      
       } 
       ++lhs; 
       ++rhs; 
      } 
      return false; 
     } 
     bool operator>(const tree& right) 
     { 
      return (right < *this); 
     } 
     bool operator<=(const tree& right) 
     { 
      return (!(right < *this)); 
     } 
     bool operator>=(const tree& right) 
     { 
      return (!(*this < right)); 
     } 
}; 
//******************************************************* 
//Relation Operators 
//******************************************************* 
template<class tree> 
bool operator==(const tree& left,const tree& right) 
{ 
    if(left.size() != right.size()) 
    { 
     return false; 
    } 

    tree::const_iterator lhs = left.cbegin(); 
    tree::const_iterator rhs = right.cbegin(); 
    while(lhs != left.cend() && rhs != right.cend()) 
    { 
     if(lhs->first != rhs->first || lhs->second != rhs->second) 
     { 
      return false; 
     } 
     ++lhs; 
     ++rhs; 
    } 
    return true; 
} 
template<class tree> 
bool operator!=(const tree& left,const tree& right) 
{ 
    return (!(left == right)); 
} 
template<class tree> 
bool operator<(const tree& left,const tree& right) 
{ 
    tree::const_iterator lhs = left.cbegin(); 
    tree::const_iterator rhs = right.cbegin(); 
    while(lhs != left.cend() && rhs != right.cend()) 
    { 
     if(lhs->first != rhs->first || lhs->second != rhs->second) 
     { 
      if(lhs->first < rhs->first || lhs->second < rhs->second) 
      { 
       return true; 
      }      
     } 
     ++lhs; 
     ++rhs; 
    } 
    return false; 
} 
template<class tree> 
bool operator>(const tree& left,const tree& right) 
{ 
    return (right < left); 
} 
template<class tree> 
bool operator<=(const tree& left,const tree& right) 
{ 
    return (!(right < left)); 
} 
template<class tree> 
bool operator>=(const tree& left,const tree& right) 
{ 
    return (!(left < right)); 
} 
}//end namespace avl 
+1

Compilare? IntelliSense NON è un compilatore e non dovrebbe essere considerato attendibile. –

+0

No, dà il seguente errore: Errore errore C2593: 'operator! =' È ambiguo –

+0

Potresti fornire un mini esempio per controllarlo, per favore? – RiaD

risposta

4

Su questa linea:

rit != myTree.rend() 

si confrontano due oggetti di tipo:

avltree<char,int>::reverse_iterator 

che a sua volta un alias per:

std::reverse_iterator<avl_iterator<char, int>::iterator> 

I definisce C++ Standard Library , nello spazio dei nomi std::, un modello operator != che è una corrispondenza esatta per r confrontare gli iteratori inversi (vedi Paragrafo 24.5 del C++ 11 Standard):

template <class Iterator1, class Iterator2> 
bool operator!=(
    const reverse_iterator<Iterator1>& x, 
    const reverse_iterator<Iterator2>& y) 

Tuttavia, è anche questo:

template<class tree> bool operator!=(const tree& left,const tree& right) 

Dal momento che il modello è vincolato (anche se il parametro del modello è denominato tree, questo non lo fa significa che il modello accetta solo alberi), anche questa è una corrispondenza esatta, ma il modello operator != per gli iteratori inversi è ancora più specializzato.

Pertanto, la chiamata dovrebbe non essere ambigua. Penso che questo sia un bug del compilatore.


Per risolvere il problema, assicurarsi che il proprio operatore di disuguaglianza per gli alberi accettare solo alberi, che è comunque una buona idea (davvero non si vuole il proprio operatore per confrontare nulla dopo tutto):

template<class T> bool operator!=(const avltree<T>& left,const avltree<T>& right) 
+0

Funziona perfettamente, grazie –

2

Il tuo operator != prova a confrontare in qualsiasi momento, incluso reverse_iterator s, puoi provare a usare

template<class T> bool operator!= (const avltree<T>& left,const avltree<T>& right) {  
    return (!(left == right)); 
} 
2

Sembra un compilatore rotto.

template<typename Iter> 
bool std::operator!=(const std::reverse_iterator<Iter>&, 
        const std::reverse_iterator<Iter>&); 

è "più specializzata rispetto"

template<class tree> 
bool avl::operator!=(const tree&, const tree&); 

quindi l'espressione rit != myTree.rend() non dovrebbe essere ambiguo.

Ancora, dichiarare qualcosa che può essere applicato != a qualsiasi due oggetti dello stesso tipo è un'idea pericolosa.

-1

Si prova a confrontare un const_reverse_iterator con un reverse_iterator, la chiamata a rend() utilizzerà sempre il sovraccarico non costante se disponibile. Una soluzione per questo dovrebbe essere ovvia. Lo stesso problema esisteva con alcune prime implementazioni di std :: set, se ricordo bene.

In ogni caso, c'è un buon approccio che avrebbe ovviare a questo problema pur essendo IMHO ancora più elegante:

for(container::iterator it=c.begin(), end=c.end(); it!=end; ++it) 
    ... 

In altre parole, sempre usare un paio di iteratori che sono dichiarati nell'intestazione del ciclo for. usando "auto" di C++ 11, questo diventa ancora più corto. Mentre il singolo call to end() non è più veloce con qualsiasi compilatore semi-moderno, personalmente lo trovo un po 'più chiaro.

+0

'rbegin()', 'rend()' sono entrambi 'reverse_iterators' – RiaD

+0

Ti manca il punto. Se preso alla lettera, questa affermazione è anche sbagliata, perché sono sovraccarichi. Un sovraccarico di ogni 'begin()' e 'end()' restituisce un 'const_reverse_iterator' e l'altro restituisce un' reverse_iterator'. Mentre la conversione da non const a const funziona ovviamente, ciò non garantisce che i confronti tra i due lavori. –