2

This relates to my previous question here.

Here's a summary of that thread: I am trying to implement a doubly-linked-list class called my_list in C++, including iterators and I want automatic implicit conversion of iterator to const_iterator.

My original thought was to have something like

template<class T>
class my_list_iterator<T>
{
    node<T> pos_;
    /* code */
    operator my_list_iterator<const T>(){return my_list_iterator<const T>(pos_);}
};

and then inside my_list define iterator as my_list_iterator<T> and const_iterator as my_list_iterator<const T>.

However, as pointed out by Miled Budneck in the previous thread, this won't work because a pointer to node<T> cannot convert to a pointer to node<const T>. He suggested I re-implement the const iterator as a pointer to const node instead.

While that works, by looking around I also found one other possible way to define the iterator class:

template<class T, class Pointer, class Reference>
class my_list_iterator {
    node<T>* pos_;
    /* code */
    operator my_list_iterator<T,const Pointer,const Reference>() {return my_list_iterator<T,const Pointer,const Reference>(pos_);}
};

Then I can define my_list<T>::iterator as my_list_iterator<T,T*,T&> and my_list<T>::const_iterator as my_list_iterator<T,const T*,const T&>. I thought the last line would take care of the implicit conversion issue, but it seems to not be used at all.

For reference, here is the complete code:

template<class T> class node {
    node(const T& t = T()):data(t),next(0),prev(0) {}
    T data;
    node* next;
    node* prev;

    friend class my_list<T>;
    template<class U,class Pointer,class Reference> friend class my_list_iterator;
};

template<class T,class Pointer,class Reference> class my_list_iterator {
    public:
            // increment and decrement operators
            my_list_iterator operator++();
            my_list_iterator operator++(int);
            my_list_iterator operator--();
            my_list_iterator operator--(int);

            // bool comparison iterators
            bool operator==(const my_list_iterator& other) const {return pos_==other.pos_;}
            bool operator!=(const my_list_iterator& other) const {return pos_!=other.pos_;}

            // member access
            Reference operator*() const {return pos_->data;}
            Pointer operator->() const {return &(pos_->data);}

            // conversion to constant
            operator my_list_iterator<T,const Pointer,const Reference>() {return pos_;}

    private:
            node<T>* pos_;
            explicit my_list_iterator(node<T>* p=0):pos_(p) {}
            friend class my_list<T>;
};

and the error message in the end

note:   no known conversion for argument 1 from ‘my_list<int>::iterator’ {aka ‘my_list_iterator<int, int*, int&>’} to ‘const my_list_iterator<int, const int*, const int&>&’

So why does this code not work? Is there any small modification I can make to make it work, or is this design impossible to implement?

John
  • 71
  • 6

1 Answers1

0

Given Pointer = T*, const Pointer is T* const, not const T*. Type substitution is not like macro expansion. const Pointer adds a top-level const to the type denoted by Pointer. Similarly, const Reference is T& const (which is automatically adjusted to T& because top-level cv-qualifiers on references are ignored) instead of const T&. (See What is the difference between const int*, const int * const, and int const *? for the difference between T* const and const T*.)

You need to use something like const std::remove_pointer<Pointer>* for this to work.

L. F.
  • 19,445
  • 8
  • 48
  • 82