Following the paradigms of SCARY iterators, there should only be a single iterator-type for contiguous iterators per value-type.
Here my code for that iterator, working with C++11+:
#include <type_traits>
#include <iterator>
template<class T, class U>
struct is_more_cv_qualified : std::integral_constant<bool, std::is_same<T, const volatile U>{}
|| std::is_same<T, const U>{} || std::is_same<T, volatile U>{}>;
struct contiguous_iterator_tag : std::random_access_iterator_tag {};
struct mutable_contiguous_iterator_tag : contiguous_iterator_tag, std::output_iterator_tag {};
template<class T>
struct contiguous_iterator_base {
constexpr bool operator==(contiguous_iterator_base other) const noexcept { return _p == other.p; }
constexpr bool operator!=(contiguous_iterator_base other) const noexcept { return _p != other.p; }
constexpr bool operator<(contiguous_iterator_base other) const noexcept { return _p < other._p; }
constexpr bool operator>(contiguous_iterator_base other) const noexcept { return _p > other._p; }
constexpr bool operator<=(contiguous_iterator_base other) const noexcept { return _p <= other._p; }
constexpr bool operator>=(contiguous_iterator_base other) const noexcept { return _p >= other._p; }
constexpr std::ptrdiff_t operator-(contiguous_iterator_base other) const noexcept { return _p - other._p; }
protected:
constexpr contiguous_iterator_base& operator=(const contiguous_iterator_base&) noexcept = default;
T* _p = nullptr;
};
template<class T>
struct contiguous_iterator : contiguous_iterator_base<std::remove_cv<T>::type>
, std::iterator<typename std::conditional<std::is_const<T>{}, contiguous_iterator_tag, mutable_contiguous_iterator_tag>::type, T> {
constexpr contiguous_iterator() noexcept = default;
template<class U, class = std::enable_if<is_more_cv_qualified<T, U>{}>::type>
constexpr contiguous_iterator(contiguous_iterator<U> other) noexcept : contiguous_iterator_base<std::remove_cv<T>::type>(other) {}
constexpr explicit contiguous_iterator(contiguous_iterator_base<std::remove_cv<T>::type> other) noexcept : decltype(other)(other) {}
constexpr explicit contiguous_iterator(T* p) noexcept { _p = const_cast<decltype(_p)>(p); }
template<class U>
constexpr contiguous_iterator<U> rebind() const noexcept { return contiguous_iterator<U>(_p); }
constexpr T* operator->() const noexcept { return _p; }
constexpr T& operator* () const noexcept { return *_p; }
constexpr T& operator[](std::ptrdiff_t d) const noexcept { return _p[d]; }
constexpr contiguous_iterator& operator++() noexcept { ++_p; return *this; }
constexpr contiguous_iterator operator++(int) noexcept { auto r = *this; ++*this; return r; }
constexpr contiguous_iterator& operator--() noexcept { --_p; return *this; }
constexpr contiguous_iterator operator--(int) noexcept { auto r = *this; --*this; return r; }
constexpr contiguous_iterator& operator+=(std::ptrdiff_t d) noexcept { _p += d; return *this; }
constexpr contiguous_iterator& operator-=(std::ptrdiff_t d) noexcept { _p -= d; return *this; }
constexpr contiguous_iterator operator+(std::ptrdiff_t d) const noexcept { return contiguous_iterator(_p) += d; }
constexpr contiguous_iterator operator-(std::ptrdiff_t d) const noexcept { return contiguous_iterator(_p) -= d; }
protected:
using contiguous_iterator_base<std::remove_cv<T>::type>::_p;
};
// smoke test
int main() {
contiguous_iterator_base<int>{};
contiguous_iterator<int> a;
contiguous_iterator<const int> b;
b = a;
a = b.rebind<int>();
//a.rebind<char>(); error
}
operator->
,operator*
andoperator[]
markedconst
since I'd find it surprising to not be able to dereference aconst
iterator. \$\endgroup\$std::iterator
(besides it is deprecated). 2) would you consider making the contiguous iterator convertible (explicitly or implicitly) to the pointer, or by means of an idiomatic function, such as.data()/data(It)
, 3) Some of standard iterators are (accidentally?) nullable and the null-state can be checked, your doesn't seem to be. \$\endgroup\$