23 Iterators library [iterators]

23.5 Iterator adaptors [predef.iterators]

23.5.4 Common iterators [iterators.common]

23.5.4.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&> common_iterator& operator=(const common_iterator<I2, S2>& x); decltype(auto) operator*(); decltype(auto) operator*() const requires dereferenceable<const I>; decltype(auto) operator->() const requires see below; common_iterator& operator++(); decltype(auto) operator++(int); template<class I2, sentinel_­for<I> S2> requires sentinel_­for<S, I2> friend 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 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 iter_difference_t<I2> operator-( const common_iterator& x, const common_iterator<I2, S2>& y); friend iter_rvalue_reference_t<I> 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 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; using value_type = iter_value_t<I>; using difference_type = iter_difference_t<I>; using pointer = see below; using reference = iter_reference_t<I>; }; }