Я работаю над контейнером, который реализует свой собственный итератор, который я использую с std :: reverse_iterator<> чтобы получить функциональность обратной итерации. Я могу назначить обратный итератор для рендеринга или запуска, но когда я пытаюсь получить доступ к любой из его функций (например,! = Или ==), я получаю это:
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>>>>>
Мой оператор итератора перегружен:
bool operator == ( const avl_iterator& rhs ) const { return ( _node == rhs._node); }
bool operator != ( const avl_iterator& rhs ) const { return ( _node != rhs._node); }
и моя реализация обратного итератора
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;
итератор 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;
Как я пользуюсь оператором
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
{
}
и класс итератора (const_iterator это то же самое, но с const value_type)
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;
}
};
и класс дерева:
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
На этой линии:
rit != myTree.rend()
Вы сравниваете два объекта типа:
avltree<char,int>::reverse_iterator
Что в свою очередь является псевдонимом для:
std::reverse_iterator<avl_iterator<char, int>::iterator>
Стандартная библиотека C ++ определяет в std::
пространство имен, шаблонное operator !=
что является точным соответствием для сравнения обратных итераторов (см. пункт 24.5 стандарта C ++ 11):
template <class Iterator1, class Iterator2>
bool operator!=(
const reverse_iterator<Iterator1>& x,
const reverse_iterator<Iterator2>& y)
Тем не менее, у вас также есть это:
template<class tree> bool operator!=(const tree& left,const tree& right)
Поскольку шаблон является неограниченным (хотя параметр шаблона называется tree
, это не означает, что шаблон будет принимать только деревья), это также точное совпадение, но шаблонное operator !=
для обратных итераторов все еще более специализирован.
Следовательно, вызов должен не быть двусмысленным Я думаю, что это ошибка компилятора.
Чтобы решить эту проблему, убедитесь, что ваш оператор неравенства для деревьев принимает только деревья, что в любом случае является хорошей идеей (вы действительно не хотите, чтобы ваш оператор сравнивал что-нибудь в конце концов):
template<class T> bool operator!=(const avltree<T>& left,const avltree<T>& right)
Ваш operator !=
пытается сравнить в любое время, в том числе reverse_iterator
s, вы можете попробовать использовать
template<class T> bool operator!= (const avltree<T>& left,const avltree<T>& right) {
return (!(left == right));
}
Похоже, сломанный компилятор.
template<typename Iter>
bool std::operator!=(const std::reverse_iterator<Iter>&,
const std::reverse_iterator<Iter>&);
«более специализированный, чем»
template<class tree>
bool avl::operator!=(const tree&, const tree&);
так что выражение rit != myTree.rend()
не должно быть двусмысленным.
Тем не менее, объявив что-то, что может применяться !=
в любой два объекта одного типа — опасная идея.
Вы пытаетесь сравнить const_reverse_iterator с reverse_iterator, вызов rend () всегда будет использовать неконстантную перегрузку, если она доступна. Исправление для этого должно быть очевидным. Та же проблема существовала с некоторыми ранними реализациями std :: set, если я правильно помню.
Во всяком случае, есть хороший подход, который обойдет эту проблему, будучи ИМХО еще более элегантным:
for(container::iterator it=c.begin(), end=c.end(); it!=end; ++it)
...
Другими словами, всегда используйте пару итераторов, которые объявлены в заголовке цикла for. используя «авто» в C ++ 11, это становится еще короче. Хотя одиночный вызов end () не является быстрым с любым наполовину современным компилятором, я лично нахожу это немного яснее.