I'm trying to make the iterator work properly, and for the inequality i != a.end().
I get the error
no know conversion from argument 2 from 'const a3::vector<int>::iterator' to 'const a3::vector<int>&
for the friend function. I need the function to check if the iterator is not equal to vector.end() and am unsure how I would do it.
Class
#include <iostream>
using std::cout;
using std::endl;
namespace a3
{
template <typename T>
class vector
{
public:
class iterator {
public:
int index_;
vector* a_;
iterator() : index_(-1), a_(0) {}
iterator(int index, vector* a) : index_(index), a_(a) {}
iterator& operator=(const iterator& itr)
{
a_ = itr.a_;
index_ = itr.index_;
return *this;
}
iterator& next() {
index_++;
return *this;
}
iterator& operator++() {
return next();
}
int& operator*() { return (*a_)[index_]; }
};
private:
T* mem_;
int sz_;
public:
vector(int sz) : sz_(sz), b_(0, this), e_(sz, this)
{
mem_ = new T[sz];
}
~vector() { delete[] mem_; }
const T& operator[](T i) const { return mem_[i]; }
T& operator[](T i) { return mem_[i]; }
const int& get_size() const { return sz_; }
const iterator& begin() { return b_; }
const iterator& end() { return e_; }
friend bool operator!=(const iterator& itr1, const vector<T>& vec1)
{
return !(itr1.index_ == vec1.end);
}
private:
iterator b_;
iterator e_;
};
}
Main Function
#include "a3_vector.cpp"
int main(int argc, char** argv)
{
using namespace a3;
vector<int> a(10); // allocate an int array of size 10
for (int i=0; i<10; ++i) a[i] = i*2;
// a now looks as follows
//0,2,4,6,8,10,12,14,16,18
// prints the content of the array
vector<int>::iterator i;
for (i = a.begin(); i != a.end(); i.next()) {
cout << *i << endl;
}
}
This is fundamentally wrong:
friend bool operator!=(const iterator& itr1, const vector<T>& vec1)
Iterator comparisons should compare iterators. What you want are comparison operators that look like this:
friend bool operator!=(const iterator& itr1, const iterator& itr2);
friend bool operator==(const iterator& itr1, const iterator& itr2);
After all, that's what this expression is trying to do:
i != a.end()
You're trying to compare two iterators. The error is just trying to convert a.end() to a const vector<T>&, since that's the match that it found for !=. Simply fix != to take an iterator as the second argument and you'll be fine.
Related
i have to implement a forward iterator on a stack based on arrays. I can't use std::vectors or anything, i just need that. My development of this program stopped when i begun with forward iterator, and in particular with the operators.
I have a method that takes a generic sequence, and from that, given an offset, creates a stack:
template <typename IterT>
stack(IterT begin, IterT end) : _stack(0), _size(0), _capacity(0) {
try {
for(; begin!=end; ++begin) {
push(static_cast<T>(*begin));
}
}
catch(...) {
clear(); //my method to destroy the stack
throw;
}
}
In my main i do the following:
int a[5] = {1, 2, 3, 4, 5};
stack<int> sint(a, a+5);
cout << sint << endl;
But when the code runs the stack is created but not printed. Can somebody help me? And also give me other helps(on code indentation, improvements, etc...) Thank you, I will post the iterator code forward.
class const_iterator {
const T* data;
unsigned int index;
public:
typedef std::forward_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
const_iterator() : data(0){}
const_iterator(const T* arr) : data(arr) {}
const_iterator(const const_iterator &other)
: data(other.data){ }
const_iterator& operator=(const const_iterator &other) {
data = other.data;
return *this;
}
~const_iterator() {
data = 0;
}
reference operator*() const {
return *data;
}
pointer operator->() const {
return &(data);
}
const_iterator operator++(int) {
const_iterator tmp(*this);
++*this;
return tmp;
}
const_iterator& operator++() {
++data;
return *this;
}
bool operator==(const const_iterator &other) const {
return data[index] == other.data[index];
}
bool operator!=(const const_iterator &other) const {
return data[index] != other.data[index] ;
}
private:
friend class stack;
const_iterator(unsigned int ind) :
index(ind){}
}; // class const_iterator
const_iterator begin() const {
cout << "begin" << _stack[_size-1] << endl;
return const_iterator(_stack[_size-1]);
}
const_iterator end() const {
cout << "end" << _stack[0] << endl;
return const_iterator(_stack[0]);
}
Last but not least i redefined the << operator to fit the iterator:
template <typename T>
std::ostream &operator<<(std::ostream &os, const stack<T> &st) {
typename stack<T>::const_iterator i, ie;
for(i = st.begin(), ie = st.end(); i!=ie; ++i){
os << *i << std::endl;
}
return os;
}
The code for the stack is the following (I omitted something for readability).
stack()
: _capacity(0), _size(0), _stack(0){}
void push (const T &value){
if (_size == _capacity){ //raddoppio la dimensione
if(_capacity == 0)
++_capacity;
_capacity *= 2;
T* tmp = new T[_capacity];
copy_n(_stack, _size, tmp);
swap(_stack, tmp);
delete[] tmp;
}
_stack[_size] = value;
++_size;
}
void pop(){
T _tmp;
if(!is_empty()){
_tmp = _stack[_size-1];
--_size;
}
}
If you want to create an iterator that looks like a pointer, you don't need index, because data plays its role. Comparison operator should compare datas, not values:
bool operator==(const const_iterator &other) const {
return data == other.data;
}
If you want to create a reverse iterator, it is slightly more complex. First, operator++ should decrement data. Second, dereference operator should return not *data, but *(data - 1). Third, data in the begin() iterator should point to stack[size], and data in the end() iterator should point to stack[0]. You don't need a destructor in any case.
I followed the previous advices and here's the edited result, still i can't figure out how to properly use the constructor in the private section
class const_iterator {
const T *data;
public:
/* ITERATOR TRAITS HERE */
const_iterator() : data(0){}
const_iterator(const T* arr) : data(arr) {}
const_iterator(const const_iterator &other)
: data(other.data){ }
const_iterator& operator=(const const_iterator &other) {
data = other.data;
return *this;
}
~const_iterator() {
data = 0;
}
reference operator*() const {
return *data;
}
pointer operator->() const {
return &(data);
}
const_iterator operator++(int) {
const_iterator tmp(*this);
++*this;
return tmp;
}
const_iterator& operator++() {
++data;
return *this;
}
bool operator==(const const_iterator &other) const {
return data == other.data;
}
bool operator!=(const const_iterator &other) const {
return data != other.data;
}
private:
friend class stack;
const_iterator(const T *d) {
data = d;
}
}; // classe const_iterator
const_iterator begin() const {
return const_iterator(_stack[_size-1]);
}
const_iterator end() const {
return const_iterator(_stack[0]);
}
I have a class which holds small numbers inside bigger integer variable. It works fine and fast and looks like this:
template
class Container<IntegerT>
static int bitsPerElement;
IntegerT data; // [0000] [0000] [0000] [0000] up to 128bits(or maybe more)
int size;
iterator as value_type return "reference" to container element:
Container::iterator
DataRef operator*()
DataRef
Container* parent;
int position;
But i got a problem of unavailability of std::sort, because it have no clue how to actually swap elements of this container (direct swapping of DataRefs is obviously pointless).
Is there any magic way to make std::sort work with it (actually to force it use custom swap function)?
Or is there decent alternative to std::sort which can handle this situation? (storing DataRefs in array is not considered as a solution)
Which is the fastest way to sort this data structure?
#ifndef INTSTORAGE_H
#define INTSTORAGE_H
#include <algorithm>
template<class T> class IntStorage;
template<class T>
class DataRef
{
public:
DataRef(IntStorage<T>* parent, int position) : m_parent(parent), m_position(position) {}
DataRef(DataRef&& o) = default;
DataRef(const DataRef& o) = default;
int value() const {return m_parent->value(m_position);}
void setValue(int value) {m_parent->setValue(m_position, value);}
DataRef& operator=(const DataRef& c)
{ setValue(c.value()); return *this; }
DataRef& operator=(const DataRef&& c)
{ setValue(c.value()); return *this; }
bool operator<(const DataRef& o) const
{ return value() < o.value(); }
IntStorage<T>* m_parent;
int m_position;
};
template<class T>
class IntStorage
{
template<typename> friend class IntStorage;
template<typename> friend class DataRef;
public:
void append(int value)
{
data |= (static_cast<T>(value) << (s_bitsPerItem * size));
++size;
}
void setValue(int index, T value)
{
data = ((~(s_mask << (s_bitsPerItem * index))) & data)
| (static_cast<T>(value) << (s_bitsPerItem * index));
}
T value(int i) const { return (data & s_mask << (i * s_bitsPerItem)) >> (i * s_bitsPerItem); }
class iterator
{
public:
using iterator_category = std::random_access_iterator_tag;
using difference_type = int;
using value_type = DataRef<T>;
using pointer = DataRef<T>*;
using reference = DataRef<T>&;
iterator(IntStorage<T>* parent, int pos = 0) : ref(parent, pos) {}
inline bool operator==(const iterator& o) const { return ref.m_parent == o.ref.m_parent && ref.m_position == o.ref.m_position;}
inline bool operator!=(const iterator& o) const { return !operator==(o);}
inline const DataRef<T>& operator*() const { return ref;}
inline DataRef<T>& operator*() { return ref; }
inline iterator& operator++() { ++ref.m_position; return *this; }
inline iterator& operator--() { --ref.m_position; return *this; }
inline int operator-(const iterator& o) const { return ref.m_position - o.ref.m_position; }
inline iterator operator+(int diff) const { return iterator(ref.m_parent, ref.m_position + diff); }
inline iterator operator-(int diff) const { return iterator(ref.m_parent, ref.m_position - diff); }
inline bool operator<(const iterator& o) const { return ref.m_position < o.ref.m_position; }
DataRef<T> ref;
};
friend class iterator;
iterator begin() {return iterator(this, 0);}
iterator end() {return iterator(this, size);}
iterator cbegin() {return iterator(this, 0);}
iterator cend() {return iterator(this, size);}
static constexpr T s_mask = 0b111111;
static constexpr int s_bitsPerItem = 6;
int size = 0;
T data = 0;
};
#endif // INTSTORAGE_H
I wrote this Vector class and one nested Iterator class and one const_Iterator class, now I have to secure my Vector so my Iterator doesn't point beyond .end() with for instance my operator ++ method and to throw an exception if i try.
so in my iterator class I cannot access .end() because its a vector method. so I was thinking, instead of pointing on values in my Iterator class I point on the whole vector but i cannot access .end() with a Vector* .
Am I on the right way to the solution and if I am how can I pass my Vector so I can use it in the way I intend to?
class Vector{
public:
using value_type= double;
using size_type= size_t;
using difference_type= ptrdiff_t;
using reference = double&;
using const_reference= const double&;
using pointer = double*;
using const_pointer= const double*;
using iterator = double*;
using const_iterator= const double*;
private:
size_t sz;
size_t max_sz;
double* values=nullptr;
class const_Iterator{
public:
using value_type = double;
using difference_type = ptrdiff_t;
using reference = double&;
using pointer = double*;
using iterator_category = std::forward_iterator_tag;
private:
double* ptr;
size_t cnt;
public:
const_Iterator(double* p){
ptr=p;
cnt=0;
}
const_Iterator& operator++ () {
ptr++;
cnt = 0;
return *this;
}
bool operator==(const const_Iterator& rop)const {
return this->ptr == rop.ptr;
}
bool operator!=(const const_Iterator& rop)const {
return this->ptr != rop.ptr;
}
const double operator* () const {
return *ptr;
}
friend Vector::difference_type operator-(const Vector::const_Iterator& lop,const Vector::const_Iterator& rop) {
return lop.ptr-rop.ptr;
}
};
class Iterator{
public:
using value_type = double;
using difference_type = ptrdiff_t;
using reference = double&;
using pointer = double*;
using iterator_category = std::forward_iterator_tag;
private:
double* ptr;
size_t cnt;
public:
Iterator(double* p){
ptr=p;
cnt=0;
}
Iterator& operator++() {
ptr++;
cnt = 0;
return *this;
}
Iterator operator++(int){
Iterator a(ptr);
ptr++;
return a;
}
bool operator==( Iterator& rop) {
return this->ptr != rop.ptr;
}
bool operator!=(const Iterator& rop) {
return this->ptr != rop.ptr;
}
double& operator*() {
return *ptr;
}
operator const_Iterator() const{
return const_Iterator(ptr);
};
};
const_Iterator end() const{return const_Iterator(values+sz);}
const_Iterator begin() const{return const_Iterator(values);}
Iterator begin() { return values; }
Iterator end() { return values + sz; }
size_t min_sz = 5;
Vector();
Vector(size_t);
Vector(const Vector&);
Vector (initializer_list<double> );
void push_back(double);
void reserve(size_t);
void pop_back();
bool empty();
void clear();
Vector& operator=(const Vector&);
const double& operator[] (size_t) const;
double& operator[] (size_t) ;
void fit_to_shrink();
size_t size()const {return sz;}
ostream& print(ostream&) const;
};
Your iterator may look like:
class Iterator{
public:
// ... using type
private:
Vector* parent;
std::size_t index;
public:
Iterator(Vector& v, std::size_t index) : ptr(&v), index(index) {}
Iterator& operator++() {
if (index == parent->size()) {
throw std::runtime_error("++ on end iterator");
}
++index;
return *this;
}
Iterator operator++(int){
Iterator old(*this);
++(*this);
return old;
}
bool operator==(const Iterator& rhs) const {
if (parent != rhs.parent) {
throw std::runtime_error("You compare iterator of different containers");
}
return index == rhs.index;
}
bool operator!=(const Iterator& rop) const { return !(*this == rhs); }
double& operator*() { return parent->at(index); } // `at` throws on invalid index
// ...
};
And your vector:
Iterator Vector::begin() { return Iterator(this, 0);}
Iterator Vector::end() { return Iterator(this, size());}
I have these 2 classes:
class iterator {
public:
Node<K,V>* n;
iterator():n(NULL){}
iterator(const iterator& iter):n(iter.n){}
explicit iterator(Node<K,V>* nodePtr):n(nodePtr) {}
void operator=(const iterator& iter);
void operator++();
Node<K,V>& operator*();
bool operator!=(const iterator& iter);
K& operator[](const Key& k)const;
V& operator[](const Val& v)const;
};
//----const_iterator-class---------------------------
class const_iterator : public iterator {
public:
const Node<K,V>* n;
const_iterator():n(NULL);
const_iterator(const const_iterator& iter):n(iter.n){}
const_iterator(const iterator& iter):n(iter.n){}
explicit const_iterator(const Node<K,V>* node):n(node){}
void operator=(const const_iterator& iter){
n=iter.n;
}
void operator++(){
n = n->next;
}
};
I want to automatically convert iterator to const_iterator in case a method gets the wrong type as a parameter. I'm trying to use:
const_iterator(iterator& iter):n(iter.n){}
why do I get a segmentation fault when trying to access what's inside iter.n (the value pointed by n) after it is converted from iterator to const_iterator?
m.begin() and .end may return a temporary?
So what you need is
class const_iterator {
public:
const_iterator(const iterator &iter) {}
};
Here is code to demonstrate such conversion:
#include <iostream>
class iterator {
public:
iterator() { i = -1; }
int i;
void bar() const { std::cout << "iterator::bar() " << i << std::endl; }
};
class const_iterator : public iterator {
public:
const_iterator(int ii) : i(ii) {}
const_iterator(const iterator &it) : i(it.i) {}
const int i;
void bar() const { std::cout << "const_iterator::bar() " << i << std::endl; }
};
void foo(const const_iterator &it) {
it.bar();
}
int main() {
iterator it;
it.i = 777;
foo(it);
return 0;
}
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
I have a custom container that I have been using for many years without issues. Recently I found out that if I define iterators for my container, I can effectively use all of the algorithms defined in <algorithm>. Not only that, it seems that thrust library (basically think CUDA version of STL for Nvidia GPUs) heavily uses iterators and I am hoping that by using them I'll be able to use that library as well.
Anyway, since this is my first try at writing my own iterators, I thought I post what I have here to ask for further assistance and make sure what I'm doing is right. So, I wrote a little array class that supports both iterator and const_iterator classes. I ran my class with a bunch of different STL algorithms and all seem to work fine but that does not necessarily mean I've got everything right! In particular, is there any operator that I miss for my iterators?
Have I defined extra unnecessary ones? Also, since most of iterator and const_iterator look similar, is there a way to prevent duplication?
I'm open to suggestions and improvements :)
Live example: http://ideone.com/7YdiQY
#include <cstddef>
#include <iostream>
#include <iterator>
#include <algorithm>
template<typename T>
class my_array{
T* data_;
std::size_t size_;
public:
// ---------------------------------
// Forward declaration
// ---------------------------------
class const_iterator;
// ---------------------------------
// iterator class
// ---------------------------------
class iterator: public std::iterator<std::random_access_iterator_tag, T>
{
public:
iterator(): p_(NULL) {}
iterator(T* p): p_(p) {}
iterator(const iterator& other): p_(other.p_) {}
const iterator& operator=(const iterator& other) {p_ = other.p_; return other;}
iterator& operator++() {p_++; return *this;} // prefix++
iterator operator++(int) {iterator tmp(*this); ++(*this); return tmp;} // postfix++
iterator& operator--() {p_--; return *this;} // prefix--
iterator operator--(int) {iterator tmp(*this); --(*this); return tmp;} // postfix--
void operator+=(const std::size_t& n) {p_ += n;}
void operator+=(const iterator& other) {p_ += other.p_;}
iterator operator+ (const std::size_t& n) {iterator tmp(*this); tmp += n; return tmp;}
iterator operator+ (const iterator& other) {iterator tmp(*this); tmp += other; return tmp;}
void operator-=(const std::size_t& n) {p_ -= n;}
void operator-=(const iterator& other) {p_ -= other.p_;}
iterator operator- (const std::size_t& n) {iterator tmp(*this); tmp -= n; return tmp;}
std::size_t operator- (const iterator& other) {return p_ - other.p_;}
bool operator< (const iterator& other) {return (p_-other.p_)< 0;}
bool operator<=(const iterator& other) {return (p_-other.p_)<=0;}
bool operator> (const iterator& other) {return (p_-other.p_)> 0;}
bool operator>=(const iterator& other) {return (p_-other.p_)>=0;}
bool operator==(const iterator& other) {return p_ == other.p_; }
bool operator!=(const iterator& other) {return p_ != other.p_; }
T& operator[](const int& n) {return *(p_+n);}
T& operator*() {return *p_;}
T* operator->(){return p_;}
private:
T* p_;
friend class const_iterator;
};
// ---------------------------------
// const_iterator class
// ---------------------------------
class const_iterator: public std::iterator<std::random_access_iterator_tag, T>
{
public:
const_iterator(): p_(NULL) {}
const_iterator(const T* p): p_(p) {}
const_iterator(const iterator& other): p_(other.p_) {}
const_iterator(const const_iterator& other): p_(other.p_) {}
const const_iterator& operator=(const const_iterator& other) {p_ = other.p_; return other;}
const const_iterator& operator=(const iterator& other) {p_ = other.p_; return other;}
const_iterator& operator++() {p_++; return *this;} // prefix++
const_iterator operator++(int) {const_iterator tmp(*this); ++(*this); return tmp;} // postfix++
const_iterator& operator--() {p_--; return *this;} // prefix--
const_iterator operator--(int) {const_iterator tmp(*this); --(*this); return tmp;} // postfix--
void operator+=(const std::size_t& n) {p_ += n;}
void operator+=(const const_iterator& other) {p_ += other.p_;}
const_iterator operator+ (const std::size_t& n) const {const_iterator tmp(*this); tmp += n; return tmp;}
const_iterator operator+ (const const_iterator& other) const {const_iterator tmp(*this); tmp += other; return tmp;}
void operator-=(const std::size_t& n) {p_ -= n;}
void operator-=(const const_iterator& other) {p_ -= other.p_;}
const_iterator operator- (const std::size_t& n) const {const_iterator tmp(*this); tmp -= n; return tmp;}
std::size_t operator- (const const_iterator& other) const {return p_ - other.p_;}
bool operator< (const const_iterator& other) const {return (p_-other.p_)< 0;}
bool operator<=(const const_iterator& other) const {return (p_-other.p_)<=0;}
bool operator> (const const_iterator& other) const {return (p_-other.p_)> 0;}
bool operator>=(const const_iterator& other) const {return (p_-other.p_)>=0;}
bool operator==(const const_iterator& other) const {return p_ == other.p_; }
bool operator!=(const const_iterator& other) const {return p_ != other.p_; }
const T& operator[](const int& n) const {return *(p_+n);}
const T& operator*() const {return *p_;}
const T* operator->() const {return p_;}
private:
const T* p_;
};
my_array()
: data_(NULL), size_(0)
{}
my_array(std::size_t size)
: data_(new T[size]), size_(size)
{}
my_array(const my_array<T>& other){
size_ = other.size_;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = other.data_[i];
}
my_array(const const_iterator& first, const const_iterator& last){
size_ = last - first;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = first[i];
}
~my_array(){
delete [] data_;
}
const my_array<T>& operator=(const my_array<T>& other){
size_ = other.size_;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = other.data_[i];
return other;
}
const T& operator[](std::size_t idx) const {return data_[idx];}
T& operator[](std::size_t& idx) {return data_[idx];}
std::size_t size(){return size_;}
iterator begin(){ return iterator(data_); }
iterator end() { return iterator(data_+size_); }
const_iterator begin() const{ return const_iterator(data_); }
const_iterator end() const { return const_iterator(data_+size_);}
};
template<typename T>
void print(T t) {
std::cout << t << std::endl;
}
int main(){
// works!
int list [] = {1, 3, 5, 2, 4, 3, 5, 10, 10};
my_array<int> a(list, list+sizeof(list)/sizeof(int));
// works!
for (my_array<int>::const_iterator it = a.begin(), end = a.end();
it != end; ++it)
std::cout << ' ' << *it;
std::cout << std::endl;
// works!
std::for_each(a.begin(), a.end(), print<int>);
std::cout << std::endl;
// works!
my_array<int> b(a.size());
std::copy(a.begin(), a.end(), b.begin());
// works!
my_array<int>::iterator end = std::remove(a.begin(), a.end(), 5);
std::for_each(a.begin(), end, print<int>);
std::cout << std::endl;
// works!
std::random_shuffle(a.begin(), end);
std::for_each(a.begin(), end, print<int>);
std::cout << std::endl;
// works!
std::cout << "Counts of 3 in array = " << std::count(a.begin(), end, 3) << std::endl << std::endl;
// works!
std::sort(a.begin(), end);
std::for_each(a.begin(), end, print<int>);
std::cout << std::endl;
// works!
if (!std::binary_search(a.begin(), a.end(), 5))
std::cout << "Removed!" << std::endl;
return 0;
}
boost iterator provides a framework to create stl-compliant iterators and to adapt existing ones.
It allows you to focus on the functionality and generates all necessary traits, typedefs for you.
iterator and const_iterator creation without much code-duplication is supported as well.
The Boost iterator_adaptor can greatly simplify your code. The documentation has e.g. this example for a linked list iterator
template <class Value>
class node_iter
: public boost::iterator_adaptor<
node_iter<Value> // Derived
, Value* // Base
, boost::use_default // Value
, boost::forward_traversal_tag // CategoryOrTraversal
>
{
private:
struct enabler {}; // a private type avoids misuse
public:
node_iter()
: node_iter::iterator_adaptor_(0) {}
explicit node_iter(Value* p)
: node_iter::iterator_adaptor_(p) {}
template <class OtherValue>
node_iter(
node_iter<OtherValue> const& other
, typename boost::enable_if<
boost::is_convertible<OtherValue*,Value*>
, enabler
>::type = enabler()
)
: node_iter::iterator_adaptor_(other.base()) {}
private:
friend class boost::iterator_core_access;
void increment() { this->base_reference() = this->base()->next(); }
};
Note that the example only provides a default constructor, a constructor taking a node pointer, a generalized copy constructor that only accepts elements that can be converted to a node pointer, and an increment function. The increment function is an implementation detail that is shared by both operator++() and operator++(int).
All the other boiler-plate is automatically being generated by deriving from boost::iterator_adaptor. That includes all the nested typedef that you could also get from deriving from std::iterator, as well as all the overloaded operators (++, *, ->, ==, !=, advance) and anything else to make it a fully Standard conforming iterator.
By passing a Value const* and using a typedef you can define a const_iterator that reuses all your code with the appropriate modifications. Studying the example now will save you enormously down the road.