c++templatescompiler-errorsc++98qualifiers

how to implicitly convert a foo<const bar> into a const foo<bar> in C++ template?


I'm making my own vector container and I'm trying to implement an iterator that works like the real one, using the C++98 standard.

This is homework so I don't want the answer just a hint as to where I should look and what I should learn to be able to tackle this problem.

So basically I'm trying to make this code work:

ft::vector<int> v (100, 100);
ft::vector<int>::iterator it = v.begin();
ft::vector<int>::const_iterator cit = it;

std::cout << (cit == it) << std::endl; //comparison 1 /// works
std::cout << (it == cit) << std::endl; //comparison 2 /// doesn't compile
std::cout << (cit + 1 == it + 1) << std::endl; //doesn't work
std::cout << (it + 1 == cit + 1) << std::endl; //doesn't work

iterator and const_iterator are typedefs like this:

typedef typename ft::iterator_vector<value_type> iterator;
typedef typename ft::iterator_vector<const value_type> const_iterator;

And value type being the type passed to the vector template.

The first comparison didn't work until I added a user-defined conversion operator in my iterator template to convert iterator<const foo> into iterator<foo> (the other way around actually as pointed out by @TedLyngmo) which is operator iterator_vector<const value_type>() const { return _p; } but the compiler says that I need now to be able to convert a iterator<const foo> into a const iterator<foo> and I have no idea how to proceed.

This is the implementation of my iterator:

template <class T>
class iterator_vector : public ft::iterator<std::random_access_iterator_tag, T> {

public:

    typedef             ft::iterator<std::random_access_iterator_tag, T>    iterator;
    typedef             ft::iterator_traits<iterator>                   iterator_traits;
    typedef typename    iterator_traits::difference_type                difference_type;
    typedef typename    iterator_traits::value_type                     value_type;
    typedef typename    iterator_traits::pointer                        pointer;
    typedef typename    iterator_traits::reference                      reference;
    typedef typename    iterator_traits::iterator_category              iterator_category;

    /*
    ** Member functions
    */

    iterator_vector(pointer p = 0) : _p(p) {}
    ~iterator_vector(void) {}

    operator iterator_vector<const value_type>() const { return _p; }

    iterator_vector& operator++() { ++_p; return *this; }
    iterator_vector operator++(int)
    {
        iterator_vector r = *this;
        ++_p;
        return r;
    }
    iterator_vector& operator--() { --_p; return *this; }
    iterator_vector operator--(int)
    {
        iterator_vector r = *this;
        --_p;
        return r;
    }
    iterator_vector operator+(size_t n) const { return iterator_vector(_p + n); }
    iterator_vector operator-(size_t n) const { return iterator_vector(_p - n); }
    iterator_vector& operator+=(size_t n) { _p += n; return *this; }
    iterator_vector& operator-=(size_t n) { _p -= n; return *this; }
    difference_type operator+(iterator_vector rhs) const { return _p + rhs._p; }
    difference_type operator-(iterator_vector rhs) const { return _p - rhs._p; }
    reference operator*(void) const { return *_p; }
    pointer operator->() const { return _p; }
    reference operator[](size_t n) const { return _p[n]; }
    bool operator==(const iterator_vector& rhs) const { return _p == rhs._p; }
    bool operator!=(const iterator_vector& rhs) const { return _p != rhs._p; }
    bool operator<(const iterator_vector& rhs) const { return _p > rhs._p; }
    bool operator>(const iterator_vector& rhs) const { return _p < rhs._p; }
    bool operator<=(const iterator_vector& rhs) const { return _p <= rhs._p; }
    bool operator>=(const iterator_vector& rhs) const { return _p >= rhs._p; }

    /*
    ** Non-member functions
    */

    friend iterator_vector operator+(size_t n, const iterator_vector& rhs) { return iterator_vector(rhs._p + n); }
    friend iterator_vector operator-(size_t n, const iterator_vector& rhs) { return iterator_vector(rhs._p - n); }

private:

    pointer _p;

};

Solution

  • It seems from your comments in your code about what is failing that you are missing a comparison function for when iterator is to the left and the const_iterator is to the right. You could add this free function:

    template<typename T>
    bool operator==(const iterator_vector<T>& lhs, const iterator_vector<const T>& rhs) {
        // just swap the order here and the implicit conversion from `iterator`
        // to `const_iterator` from `lhs` solves the rest:
        return rhs == lhs;
    }
    

    I added a user-defined conversion operator in my iterator template to convert iterator<const foo> into iterator<foo>

    No, you added an implicit conversion the other way around. That is, from iterator to const_iterator - which is good!


    An alternative could be to make the two iterators friends to not have to implement similar swapping lhs with rhs functions for all your operators. The operators in your template would then become:

    // define these before your class template (borrowed from C++11):
    template< class T > struct remove_const          { typedef T type; };
    template< class T > struct remove_const<const T> { typedef T type; };
    
    //... in your class template:
    friend class iterator_vector<typename remove_const<T>::type>;
    friend class iterator_vector<const T>;
    
    template<typename U>
    bool operator==(const iterator_vector<U>& rhs) const { return _p == rhs._p; }
    template<typename U>
    bool operator!=(const iterator_vector<U>& rhs) const { return _p != rhs._p; }
    template<typename U>
    bool operator<(const iterator_vector<U>& rhs) const { return _p > rhs._p; }
    template<typename U>
    bool operator>(const iterator_vector<U>& rhs) const { return _p < rhs._p; }
    template<typename U>
    bool operator<=(const iterator_vector<U>& rhs) const { return _p <= rhs._p; }
    template<typename U>
    bool operator>=(const iterator_vector<U>& rhs) const { return _p >= rhs._p; }