What types should be used for iterator::reference and const_iterator::reference?
If you want to find out what type you should assign to your iterator traits (iterator::reference
, iterator::pointer
, etc) you can try and mimic what std::vector
does, the following program when compiled will tell you everything you need to know (live demo)
#include <vector>
template <typename...>
struct WhichType;
int main() {
auto vec = std::vector<int>{};
WhichType<typename decltype(vec.begin())::difference_type>{};
WhichType<typename decltype(vec.begin())::value_type>{};
WhichType<typename decltype(vec.begin())::pointer>{};
WhichType<typename decltype(vec.begin())::reference>{};
WhichType<typename decltype(vec.begin())::iterator_category>{};
WhichType<typename decltype(vec.cbegin())::difference_type>{};
WhichType<typename decltype(vec.cbegin())::value_type>{};
WhichType<typename decltype(vec.cbegin())::pointer>{};
WhichType<typename decltype(vec.cbegin())::reference>{};
WhichType<typename decltype(vec.cbegin())::iterator_category>{};
}
what types should be returned by operator* for iterator, const iterator and const_iterator?
operator*
for regular non const_
iterators should return a mutable reference to the underlying type, there is no ambiguity there if the semantics of the container allow that. For example std::map
iterators return const references to the key type, because the key should not be modified in a std::map
(see https://stackoverflow.com/a/32510343/5501675)
const iterator
conveys the same meaning that T* const
, const std::unique_ptr<int>
do, they represent const pointers to non const data. So you can use the pointer to modify the data they point to, but you cannot modify the pointer itself. In this case the iterator acts like a pointer. So you cannot modify the iterator, but you can modify what the iterator points to (live demo)
As a consequence of the iterator being const
you cannot call the operator++()
(or the preincrement operator) to advance the iterator to the next position. You cannot do this because the method is not const. Because of this most code never uses iterators that are const themself. You are better off using a const reference to the underlying type.
const_iterator
is defined to solve the issue of iterators returning const references to the underlying type. So they return const references to the underlying type. Live demo
As to what typedefs it should have, the first code example when compiled should tell you that
does a const iterator allow mutable access to the underlying container?
Yes, if the container does. For example std::vector<int>
does, whereas std::map<int, int>
does not allow mutable access to its key types
Or should the definition of const_iterator::reference be T& without const?
See the live demo above, when you compile the code you will see that it is a const T&