views:

1562

answers:

3

I've written my own container template with an iterator. How do I implement const_iterator?

template <class T>
class my_container {
 private:
  ...

 public:
  my_container() : ... { }
  ~my_container() { }

  class iterator : public std::iterator<std::bidirectional_iterator_tag, T> {
  public: ...
+1  A: 

The only difference should be that when you de-reference a const iterator you get a const reference rather than a reference to the object in the container.

Martin York
What about methods that take iterators as arguments or return iterators? I have to overload them for const_iterators? Seems like a bunch of repeated code.
Posco Grubb
iterators should be convertible into const_iterators, so you won't have to overload if you only need a const_iterator. You do for functions like begin(), end(), but there's no way around that, as const also part of the method's signature.
Roger Pate
@ Posco Grubb: No. If you have methods that take iterators then template's them. The method should work for anything that acts like an iterator. If the method requires an iterator rather than a const_iterator the compiler will generate the appropriate error.
Martin York
also, add a templated converting constructor to const_iterator that takes a iterator. Then you can conveniently convert from a non-const to a const_iterator
Johannes Schaub - litb
A: 

I find the easiest way to implement iterators is boost::iterator. If you want to roll your own, I think the signature should be:

class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const T> {

with the implementation the same (assuming you are using reference_type and so forth in your function signatures)

Todd Gardner
I was surprised to find that iterator_traits<vector<int>::const_iterator>::value_type is int, not int const (T, instead of const T in your code). I think with const makes more sense though. However, bottom-line is if you want to match up with the standard containers, you need to use non-const T.
Roger Pate
Lou Franco
Todd Gardner
I would also prefer a non-const T. So that functions that return value_type return a non-const one (so move constructors could be written and are effective). Also, compilers could warn if such a function like Iter::value_type f(Iter b, Iter e); is generated (there are no const rvalues of non-class type).
Johannes Schaub - litb
Hm wow. A lot of things I had not considered. What I wanted is an iterator such that the value (T) cannot be changed while the container being iterated over (my_container) can be changed.I also wanted compatibility with STL, but if I understand the above comments correctly, an STL const_iterator is the opposite: it allows modifying the object contained, and disallows modifying the container.
Posco Grubb
No, the STL doesn't allow the container or it's values to be modified through a const iterator (logical constness), as the reference_type (used for pass by reference) of const_iterator typedefed to a reference to const. The above discussion was pertaining to value_type (used for pass by value) and if for Container<T> value_type of const_iterator was typedefed to T, or const T. I had assumed the latter, which was incorrect.
Todd Gardner
A: 

Roger Pate, value_types are "simple". I suspect you'll see the const if you look at iterator_traits::const_iterator>::reference, which I think will be "const int&".

Ben FrantzDale