简体   繁体   中英

How to write a random access custom iterator that can be used with STL algorithms?

#include <iostream>
#include <vector>
#include <algorithm>

template <typename T>
class _iterator
{
    T* ptr;

public:

    using iterator_category = std::random_access_iterator_tag;
    using value_type        = T;
    using reference         = T&;
    using pointer           = T*;
    using difference_type   = unsigned long long;

    _iterator(T* ptr) : ptr(ptr) {}

    reference operator* () { return *ptr; }
    pointer   operator->() { return  ptr; }

    _iterator& operator++() { ptr++; return *this; }
    _iterator& operator--() { ptr--; return *this; }

    difference_type operator-(const _iterator& it) { return this->ptr - it.ptr; }

    _iterator operator+(const difference_type& diff) { return _iterator(ptr + diff); }
    _iterator operator-(const difference_type& diff) { return _iterator(ptr - diff); }

    bool operator==(const _iterator& it) { return this->ptr == it.ptr; }
    bool operator!=(const _iterator& it) { return this->ptr != it.ptr; }
    bool operator< (const _iterator& it) { return this->ptr <  it.ptr; }

    operator _iterator<const T>() const { return _iterator<const T>(ptr); }
};

template <typename T>
class X
{
    std::vector<T> data;

public:

    using iterator = _iterator<T>;
    using const_iterator = _iterator<const T>;

    void push_back(T t)
    {
        data.push_back(t);
    }

    iterator begin()
    {
        return iterator(&data[0]);
    }

    iterator end()
    {
        return iterator(&data[0] + data.size());
    }
};

int main()
{
    X<int> x;

    for (int i = 9; i >= 0; i--)
        x.push_back(i);

    // 1 ------------------------------------------------------------------------

    // C2780    'void std::_Sort_unchecked(_RanIt,_RanIt,iterator_traits<_Iter>::difference_type,_Pr)': expects 4 arguments - 3 provided
    // C2672    '_Sort_unchecked': no matching overloaded function found
    // C2678    binary '-': no operator found which takes a left - hand operand of type 'const _RanIt' (or there is no acceptable conversion)

    std::sort(x.begin(), x.end());


    // 2 ------------------------------------------------------------------------

    // C2666    '_iterator<T>::operator -': 2 overloads have similar conversions
    // C2512    '_iterator<T>': no appropriate default constructor available

    for (X<int>::iterator it = x.end() - 1; it >= x.begin(); --it)
        std::cout << *it << ' ';
    std::cout << std::endl;
}

I'm trying to write a random access iterator for a custom container. I'm facing couple of problems:

  1. Can't use STL algorithms on the custom container.
  2. If I subtract a number from an iterator, I get an error telling me that I have 2 overloads.

Errors are written above each peice of code corresponding to it. Also I'm not sure if the way I'm defining iterator and const_iterator is a valid way or not. What am I doing wrong here and how to fix them?

// C2678    binary '-': no operator found which takes a left - hand operand of type 'const _RanIt' (or there is no acceptable conversion)

If you mark the following function as const :

difference_type operator-(const _iterator& it) const { return this->ptr - it.ptr; }

You'll start fixing some of the problems. I didn't check if this covered all the cases. But in general, making everything you can const helps a lot.

I needed to mark the functions and operators as const as well as writing a difinition for the operator[] . Optionally I can providing the reset of the relational operators ( > , >= , <= ) in case I wanted to use them. Here is the working code:

#include <iostream>
#include <vector>
#include <algorithm>

template <typename T>
class _iterator
{
    T* ptr;

public:

    using iterator_category = std::random_access_iterator_tag;
    using value_type        = T;
    using reference         = T&;
    using pointer           = T*;
    using difference_type   = unsigned long long;

    _iterator(T* ptr) : ptr(ptr) {}

    reference operator* () const { return *ptr; }
    pointer   operator->() const { return    ptr; }

    _iterator& operator++() { ptr++; return *this; }
    _iterator& operator--() { ptr--; return *this; }

    difference_type operator-(const _iterator& it) const { return this->ptr - it.ptr; }

    _iterator operator+(const difference_type& diff) const { return _iterator(ptr + diff); }
    _iterator operator-(const difference_type& diff) const { return _iterator(ptr - diff); }

    reference operator[] (const difference_type& offset) const { return *(*this + offset); }

    bool operator==(const _iterator& it) const { return this->ptr == it.ptr; }
    bool operator!=(const _iterator& it) const { return this->ptr != it.ptr; }
    bool operator< (const _iterator& it) const { return this->ptr <  it.ptr; }
    bool operator> (const _iterator& it) const { return this->ptr >  it.ptr; }
    bool operator>=(const _iterator& it) const { return !(this->ptr <  it.ptr); }
    bool operator<=(const _iterator& it) const { return !(this->ptr >  it.ptr); }

    operator _iterator<const T>() const { return _iterator<const T>(ptr); }
};

template <typename T>
class X
{
    std::vector<T> data;

public:

    using iterator = _iterator<T>;
    using const_iterator = _iterator<const T>;

    void push_back(T t)
    {
        data.push_back(t);
    }

    iterator begin()
    {
        return iterator(&data[0]);
    }

    iterator end()
    {
        return iterator(&data[0] + data.size());
    }
};

int main()
{
    X<int> x;

    for (int i = 0; i < 10; i++)
        x.push_back(i);

    std::sort(x.begin(), x.end(), std::greater<>());

    for (X<int>::iterator it = x.end() - 1; it >= x.begin(); --it)
        std::cout << *it << ' ';
    std::cout << std::endl;
}

Output:

0 1 2 3 4 5 6 7 8 9

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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