24 Iterators library [iterators]

24.5 Iterator adaptors [predef.iterators]

24.5.5 Common iterators [iterators.common]

24.5.5.1 Class template common_iterator [common.iterator]

Class template common_iterator is an iterator/sentinel adaptor that is capable of representing a non-common range of elements (where the types of the iterator and sentinel differ) as a common range (where they are the same).
It does this by holding either an iterator or a sentinel, and implementing the equality comparison operators appropriately.
[Note 1: 
The common_iterator type is useful for interfacing with legacy code that expects the begin and end of a range to have the same type.
— end note]
[Example 1: template<class ForwardIterator> void fun(ForwardIterator begin, ForwardIterator end); list<int> s; // populate the list s using CI = common_iterator<counted_iterator<list<int>::iterator>, default_sentinel_t>; // call fun on a range of 10 ints fun(CI(counted_iterator(s.begin(), 10)), CI(default_sentinel)); — end example]
namespace std { template<input_or_output_iterator I, sentinel_for<I> S> requires (!same_as<I, S> && copyable<I>) class common_iterator { public: constexpr common_iterator() requires default_initializable<I> = default; constexpr common_iterator(I i); constexpr common_iterator(S s); template<class I2, class S2> requires convertible_to<const I2&, I> && convertible_to<const S2&, S> constexpr common_iterator(const common_iterator<I2, S2>& x); template<class I2, class S2> requires convertible_to<const I2&, I> && convertible_to<const S2&, S> && assignable_from<I&, const I2&> && assignable_from<S&, const S2&> constexpr common_iterator& operator=(const common_iterator<I2, S2>& x); constexpr decltype(auto) operator*(); constexpr decltype(auto) operator*() const requires dereferenceable<const I>; constexpr auto operator->() const requires see below; constexpr common_iterator& operator++(); constexpr decltype(auto) operator++(int); template<class I2, sentinel_for<I> S2> requires sentinel_for<S, I2> friend constexpr bool operator==( const common_iterator& x, const common_iterator<I2, S2>& y); template<class I2, sentinel_for<I> S2> requires sentinel_for<S, I2> && equality_comparable_with<I, I2> friend constexpr bool operator==( const common_iterator& x, const common_iterator<I2, S2>& y); template<sized_sentinel_for<I> I2, sized_sentinel_for<I> S2> requires sized_sentinel_for<S, I2> friend constexpr iter_difference_t<I2> operator-( const common_iterator& x, const common_iterator<I2, S2>& y); friend constexpr decltype(auto) iter_move(const common_iterator& i) noexcept(noexcept(ranges::iter_move(declval<const I&>()))) requires input_iterator<I>; template<indirectly_swappable<I> I2, class S2> friend constexpr void iter_swap(const common_iterator& x, const common_iterator<I2, S2>& y) noexcept(noexcept(ranges::iter_swap(declval<const I&>(), declval<const I2&>()))); private: variant<I, S> v_; // exposition only }; template<class I, class S> struct incrementable_traits<common_iterator<I, S>> { using difference_type = iter_difference_t<I>; }; template<input_iterator I, class S> struct iterator_traits<common_iterator<I, S>> { using iterator_concept = see below; using iterator_category = see below; // not always present using value_type = iter_value_t<I>; using difference_type = iter_difference_t<I>; using pointer = see below; using reference = iter_reference_t<I>; }; }

24.5.5.2 Associated types [common.iter.types]

The nested typedef-name iterator_category of the specialization of iterator_traits for common_iterator<I, S> is defined if and only if iter_difference_t<I> is an integral type.
In that case, iterator_category denotes forward_iterator_tag if the qualified-id iterator_traits<I>​::​iterator_category is valid and denotes a type that models derived_from<forward_iterator_tag>; otherwise it denotes input_iterator_tag.
The remaining nested typedef-names of the specialization of iterator_traits for common_iterator<I, S> are defined as follows:
  • iterator_concept denotes forward_iterator_tag if I models forward_iterator; otherwise it denotes input_iterator_tag.
  • Let a denote an lvalue of type const common_iterator<I, S>.
    If the expression a.operator->() is well-formed, then pointer denotes decltype(a.operator->()).
    Otherwise, pointer denotes void.

24.5.5.3 Constructors and conversions [common.iter.const]

constexpr common_iterator(I i);
Effects: Initializes v_ as if by v_{in_place_type<I>, std​::​move(i)}.
constexpr common_iterator(S s);
Effects: Initializes v_ as if by v_{in_place_type<S>, std​::​move(s)}.
template<class I2, class S2> requires convertible_to<const I2&, I> && convertible_to<const S2&, S> constexpr common_iterator(const common_iterator<I2, S2>& x);
Preconditions: x.v_.valueless_by_exception() is false.
Effects: Initializes v_ as if by v_{in_place_index<i>, get<i>(x.v_)}, where i is x.v_.index().
template<class I2, class S2> requires convertible_to<const I2&, I> && convertible_to<const S2&, S> && assignable_from<I&, const I2&> && assignable_from<S&, const S2&> constexpr common_iterator& operator=(const common_iterator<I2, S2>& x);
Preconditions: x.v_.valueless_by_exception() is false.
Effects: Equivalent to:
  • If v_.index() == x.v_.index(), then get<i>(v_) = get<i>(x.v_).
  • Otherwise, v_.emplace<i>(get<i>(x.v_)).
where i is x.v_.index().
Returns: *this.

24.5.5.4 Accessors [common.iter.access]

constexpr decltype(auto) operator*(); constexpr decltype(auto) operator*() const requires dereferenceable<const I>;
Preconditions: holds_alternative<I>(v_) is true.
Effects: Equivalent to: return *get<I>(v_);
constexpr auto operator->() const requires see below;
The expression in the requires-clause is equivalent to: indirectly_readable<const I> && (requires(const I& i) { i.operator->(); } || is_reference_v<iter_reference_t<I>> || constructible_from<iter_value_t<I>, iter_reference_t<I>>)
Preconditions: holds_alternative<I>(v_) is true.
Effects:
  • If I is a pointer type or if the expression get<I>(v_).operator->() is well-formed, equivalent to: return get<I>(v_);
  • Otherwise, if iter_reference_t<I> is a reference type, equivalent to: auto&& tmp = *get<I>(v_); return addressof(tmp);
  • Otherwise, equivalent to: return proxy(*get<I>(v_)); where proxy is the exposition-only class: class proxy { iter_value_t<I> keep_; constexpr proxy(iter_reference_t<I>&& x) : keep_(std::move(x)) {} public: constexpr const iter_value_t<I>* operator->() const noexcept { return addressof(keep_); } };

24.5.5.5 Navigation [common.iter.nav]

constexpr common_iterator& operator++();
Preconditions: holds_alternative<I>(v_) is true.
Effects: Equivalent to ++get<I>(v_).
Returns: *this.
constexpr decltype(auto) operator++(int);
Preconditions: holds_alternative<I>(v_) is true.
Effects: If I models forward_iterator, equivalent to: common_iterator tmp = *this; ++*this; return tmp;
Otherwise, if requires(I& i) { { *i++ } -> can-reference; } is true or indirectly_readable<I> && constructible_from<iter_value_t<I>, iter_reference_t<I>> && move_constructible<iter_value_t<I>> is false, equivalent to: return get<I>(v_)++;
Otherwise, equivalent to: postfix-proxy p(**this); ++*this; return p; where postfix-proxy is the exposition-only class: class postfix-proxy { iter_value_t<I> keep_; constexpr postfix-proxy(iter_reference_t<I>&& x) : keep_(std::forward<iter_reference_t<I>>(x)) {} public: constexpr const iter_value_t<I>& operator*() const noexcept { return keep_; } };

24.5.5.6 Comparisons [common.iter.cmp]

template<class I2, sentinel_for<I> S2> requires sentinel_for<S, I2> friend constexpr bool operator==( const common_iterator& x, const common_iterator<I2, S2>& y);
Preconditions: x.v_.valueless_by_exception() and y.v_.valueless_by_exception() are each false.
Returns: true if i == j, and otherwise get<i>(x.v_) == get<j>(y.v_), where i is x.v_.index() and j is y.v_.index().
template<class I2, sentinel_for<I> S2> requires sentinel_for<S, I2> && equality_comparable_with<I, I2> friend constexpr bool operator==( const common_iterator& x, const common_iterator<I2, S2>& y);
Preconditions: x.v_.valueless_by_exception() and y.v_.valueless_by_exception() are each false.
Returns: true if i and j are each 1, and otherwise get<i>(x.v_) == get<j>(y.v_), where i is x.v_.index() and j is y.v_.index().
template<sized_sentinel_for<I> I2, sized_sentinel_for<I> S2> requires sized_sentinel_for<S, I2> friend constexpr iter_difference_t<I2> operator-( const common_iterator& x, const common_iterator<I2, S2>& y);
Preconditions: x.v_.valueless_by_exception() and y.v_.valueless_by_exception() are each false.
Returns: 0 if i and j are each 1, and otherwise get<i>(x.v_) - get<j>(y.v_), where i is x.v_.index() and j is y.v_.index().

24.5.5.7 Customizations [common.iter.cust]

friend constexpr decltype(auto) iter_move(const common_iterator& i) noexcept(noexcept(ranges::iter_move(declval<const I&>()))) requires input_iterator<I>;
Preconditions: holds_alternative<I>(i.v_) is true.
Effects: Equivalent to: return ranges​::​iter_move(get<I>(i.v_));
template<indirectly_swappable<I> I2, class S2> friend constexpr void iter_swap(const common_iterator& x, const common_iterator<I2, S2>& y) noexcept(noexcept(ranges::iter_swap(declval<const I&>(), declval<const I2&>())));
Preconditions: holds_alternative<I>(x.v_) and holds_alternative<I2>(y.v_) are each true.
Effects: Equivalent to ranges​::​iter_swap(get<I>(x.v_), get<I2>(y.v_)).