简体   繁体   English

对于std :: reverse_iterator c ++,operator!=不明确

[英]Operator != is ambiguous for std::reverse_iterator c++

I am working on a container that implements its own iterator, which I am using with std::reverse_iterator<> to get reverse iteration functionality. 我正在研究一个实现自己的迭代器的容器,我正在使用它与std :: reverse_iterator <>来获得反向迭代功能。 I can assign the reverse iterator to rend or rbegin, but when i try to access any of its functionality (such as != or ==) I get this: 我可以将反向迭代器分配给rend或rbegin,但是当我尝试访问它的任何功能(例如!=或==)时,我得到:

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

My iterator operator overloads: 我的迭代器运算符重载:

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

and my implementation of reverse iterator 和我的反向迭代器的实现

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;

and the iterator typedefs: 和迭代器typedef:

    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;

How I'm using the operator 我是如何使用运营商的

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

and the iterator class (const_iterator is the same thing but with a const value_type) 和iterator类(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;
    }
};

and the tree class: 和树类:

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

On this line: 在这一行:

rit != myTree.rend()

You are comparing two objects of type: 您正在比较两个类型的对象:

avltree<char,int>::reverse_iterator

Which is in turn an alias for: 这又是别名:

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

The C++ Standard Library defines, in the std:: namespace, a templated operator != which is an exact match for comparing reverse iterators (see Paragraph 24.5 of the C++11 Standard): C ++标准库在std:: namespace中定义了一个模板化operator != ,它与比较反向迭代器完全匹配(参见C ++ 11标准的第24.5节):

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

However, you also have this: 但是,你也有这个:

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

Since the template is unconstrained (even though the template parameter is named tree , this doesn't mean the template will only accept trees), this is also an exact match, but the templated operator != for reverse iterators is still more specialized. 由于模板是不受约束的(即使模板参数名为tree ,这并不意味着模板只接受树),这也是精确匹配,但模板化operator !=反向迭代器仍然更加专业化。

Therefore, the call should not be ambiguous. 因此,呼叫应该含糊不清。 I think this is a compiler bug. 我认为这是一个编译器错误。


To fix the issue, make sure your inequality operator for trees only accept trees, which is anyway a good idea (you really don't want your operator to compare anything after all): 要解决这个问题,请确保树的不等运算符只接受树,这无论如何都是一个好主意(你真的不希望你的运算符毕竟比较任何东西 ):

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

Your operator != tries to compare any time, including reverse_iterator s, you may try use 您的operator !=尝试比较任何时间,包括reverse_iterator ,您可以尝试使用

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

Seems like a broken compiler. 看起来像一个破碎的编译器。

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

is "more specialized than" 是“更专业”

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

so the expression rit != myTree.rend() should not be ambiguous. 所以表达式rit != myTree.rend()不应该含糊不清。

Still, declaring something that can apply != to any two objects of the same type is a dangerous idea. 仍然,声明可以应用的东西!= 任何两个相同类型的对象是一个危险的想法。

You try to compare a const_reverse_iterator to a reverse_iterator, the call to rend() will always use the non-const overload if available. 您尝试将const_reverse_iterator与reverse_iterator进行比较,对rend()的调用将始终使用非const重载(如果可用)。 A fix for this should be obvious. 解决这个问题应该是显而易见的。 The same problem existed with some early std::set implementations, if I remember correctly. 如果我没记错的话,一些早期的std :: set实现存在同样的问题。

Anyhow, there's a good approach that would work around this issue while being IMHO even more elegant: 无论如何,有一个很好的方法可以解决这个问题,而恕我直言更优雅:

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

In other words, always use a pair of iterators that are declared in the for-loop's header. 换句话说,始终使用在for-loop的头中声明的一对迭代器。 using C++11's "auto", this becomes even shorter. 使用C ++ 11的“自动”,这变得更短。 While the single call to end() is not faster with any halfway-modern compiler, I personally find it a tiny bit clearer. 虽然使用任何中途 - 现代编译器对end()的单次调用并不快,但我个人觉得它更清晰一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM