I came up with this solution. Not very "sexy", but it should work:
#include <type_traits>
#include <iterator>
#include <utility>
#include <boost/optional.hpp>
namespace pair_iterator {
template <class A, class B, class Pair>
class PairIterator {
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = std::common_type_t<A, B>;
using difference_type = std::ptrdiff_t;
using pointer = std::add_pointer_t<value_type>;
using reference = std::add_lvalue_reference_t<value_type>;
using const_reference = std::add_lvalue_reference_t<const value_type>;
private:
boost::optional<Pair &> pair = {};
difference_type index = 2;
public:
PairIterator(
const boost::optional<Pair &> &pair = {},
difference_type index = 2
) : pair(pair), index(index) {}
// Iterator
PairIterator(PairIterator&&) = default;
PairIterator(const PairIterator&) = default;
PairIterator &operator =(PairIterator&&) = default;
PairIterator &operator =(const PairIterator&) = default;
~PairIterator() = default;
void swap(PairIterator &other) {
std::swap(pair, other.pair);
std::swap(index, other.index);
}
reference operator *() {
return index == 0 ? pair->first : pair->second;
}
const_reference operator *() const {
return index == 0 ? pair->first : pair->second;
}
PairIterator &operator ++() {
++index;
return *this;
}
// InputIterator
bool operator ==(const PairIterator &other) const {
return index == other.index;
}
bool operator !=(const PairIterator &other) const {
return index != other.index;
}
PairIterator operator ++(int) const {
return { pair, index+1 };
}
// ForwardIterator
// BidirectionalIterator
PairIterator &operator --() {
--index;
return *this;
}
PairIterator operator --(int) const {
return { pair, index-1 };
}
// RandomAccessIterator
PairIterator &operator +=(difference_type n) {
index += n;
return *this;
}
PairIterator operator +(difference_type n) const {
return { pair, index+n };
}
PairIterator &operator -=(difference_type n) {
index -= n;
return *this;
}
PairIterator operator -(difference_type n) const {
return { pair, index-n };
}
difference_type operator -(const PairIterator &other) const {
return index - other.index;
}
reference operator [](difference_type n) {
return (index+n) == 0 ? pair->first : pair->second;
}
const_reference operator [](difference_type n) const {
return (index+n) == 0 ? pair->first : pair->second;
}
bool operator <(const PairIterator &other) const {
return index < other.index;
}
bool operator >(const PairIterator &other) const {
return index > other.index;
}
bool operator <=(const PairIterator &other) const {
return index <= other.index;
}
bool operator >=(const PairIterator &other) const {
return index >= other.index;
}
};
template <class A, class B>
auto begin(std::pair<A, B> &pair) ->
PairIterator<A, B, std::pair<A, B>> {
return { pair, 0 };
}
template <class A, class B>
auto end(std::pair<A, B> &pair) ->
PairIterator<A, B, std::pair<A, B>> {
return { pair, 2 };
}
template <class A, class B>
auto begin(const std::pair<A, B> &pair) ->
PairIterator<const A, const B, const std::pair<A, B>> {
return { pair, 0 };
}
template <class A, class B>
auto end(const std::pair<A, B> &pair) ->
PairIterator<const A, const B, const std::pair<A, B>> {
return { pair, 2 };
}
} // namespace pair_iterator
namespace std {
using pair_iterator::begin;
using pair_iterator::end;
} // namespace std