c++iteratorgcc8

Custom Iterators


I tried to implement iterators for a class of mine and surprisingly I got the following:

warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second

candidate 1: 'Iterator Iterator::operator+(const ptrdiff_t&) [with T = int; ptrdiff_t = long long int]'

candidate 2: 'operator+(int, unsigned int)'

Here's the Iterator code:

template<typename T>
class Iterator {

public:

    Iterator(T *p = nullptr) { this->ptr = p; }
    Iterator(const Iterator<T>& iter) = default;

    Iterator<T>& operator=(const Iterator<T>& iter) = default;
    Iterator<T>& operator=(T* p) { this->ptr = p; return *this; }

    operator bool() const { return this->ptr ? true : false; }

    bool operator==(const Iterator<T>& p) const { return this->ptr == p.getConstPtr(); }
    bool operator!=(const Iterator<T>& p) const { return this->ptr != p.getConstPtr(); }

    Iterator<T>& operator+=(const ptrdiff_t& v) { this->ptr += v; return *this; }
    Iterator<T>& operator-=(const ptrdiff_t& v) { this->ptr -= v; return *this; }
    Iterator<T>& operator++() { ++this->ptr; return *this; }
    Iterator<T>& operator--() { --this->ptr; return *this; }
    Iterator<T> operator++(int) { auto temp(*this); ++this->ptr; return temp; }
    Iterator<T> operator--(int) { auto temp(*this); --this->ptr; return temp; }
    Iterator<T> operator+(const ptrdiff_t& v) { auto oldPtr = this->ptr; this->ptr += v; auto temp(*this); this->ptr = oldPtr; return temp; }
    Iterator<T> operator-(const ptrdiff_t& v) { auto oldPtr = this->ptr; this->ptr -= v; auto temp(*this); this->ptr = oldPtr; return temp; }

    ptrdiff_t operator-(const Iterator<T>& p) { return std::distance(p.getPtr(), this->getPtr()); }

    T& operator*() { return *(this->ptr); }
    const T& operator*() const { return *(this->ptr); }
    T* operator->() { return this->ptr; }

    T* getPtr() const { return this->ptr; }
    const T* getConstPtr() const { return this->ptr; }

private:

    T *ptr;

};

And here's how I typedef it inside my class:

template<typename T>
class ExampleClass {
    
public:

   // ...

   typedef Iterator<T>       iterator;
   typedef Iterator<const T> const_iterator;

   // ...

   iterator begin() { return iterator(&this->ptr()[0]); }
   iterator end() { return iterator(&this->ptr()[this->size()]); }
   const_iterator cbegin() { return const_iterator(&this->ptr()[0]); }
   const_iterator cend() { return const_iterator(&this->ptr()[this->size()]); }

   // ...

   // A function where I use the operator+
   void slice(unsigned int first, unsigned int last) {
        // ...
        auto it = this->begin() + first; // <--------
        // ...
   }

};

Maybe I am missing something but how (Iterator, ptrdiff_t) and (int, unsigned int) are ambiguous?


Solution

  • I haven't compiled this, but the problem appears to be that operator bool(); it provides an implicit conversion to bool, which is, in turn, convertible to int. Iterators in general don't provide their own validation, so this is unusual. If you need it, mark it explicit. That will prevent the implicit conversion.