Files
2025-10-25 03:02:53 +03:00

22 KiB
Raw Permalink Blame History

[iterators.common]

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]

1

#

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.

2

#

[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]

3

#

[Example 1: templatevoid fun(ForwardIterator begin, ForwardIterator end);

list s;// populate the list susing CI = common_iterator<counted_iterator<list::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 S>requires (same_as<I, S> && copyable)class common_iterator {public:constexpr common_iterator() requires default_initializable = 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*() constrequires dereferenceable; constexpr auto operator->() constrequires see below; constexpr common_iterator& operator++(); constexpr decltype(auto) operator++(int); template<class I2, sentinel_for 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 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 I2, sized_sentinel_for S2>requires sized_sentinel_for<S, I2>friend constexpr iter_difference_t 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; template<indirectly_swappable 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; }; 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 presentusing value_type = iter_value_t; using difference_type = iter_difference_t; using pointer = see below; using reference = iter_reference_t; };}

24.5.5.2 Associated types [common.iter.types]

1

#

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 is an integral type.

In that case,iterator_category denotes forward_iterator_tag if the qualified-id iterator_traits::iterator_category is valid and denotes a type that models derived_from<forward_iterator_tag>; otherwise it denotes input_iterator_tag.

2

#

The remaining nested typedef-names of the specialization ofiterator_traits for common_iterator<I, S> are defined as follows:

  • (2.1)

    iterator_concept denotes forward_iterator_tag if I models forward_iterator; otherwise it denotes input_iterator_tag.

  • (2.2)

    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);

1

#

Effects: Initializes v_ as if by v_{in_place_type, std::move(i)}.

🔗

constexpr common_iterator(S s);

2

#

Effects: Initializes v_ as if byv_{in_place_type, std::move(s)}.

🔗

template<class I2, class S2> requires [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<const I2&, I> && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<const S2&, S> constexpr common_iterator(const common_iterator<I2, S2>& x);

3

#

Hardened preconditions: x.v_.valueless_by_exception() is false.

4

#

Effects: Initializes v_ as if byv_{in_place_index, get(x.v_)}, where i is x.v_.index().

🔗

template<class I2, class S2> requires [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<const I2&, I> && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<const S2&, S> && [assignable_from](concept.assignable#concept:assignable_from "18.4.8Concept assignable_­from[concept.assignable]")<I&, const I2&> && [assignable_from](concept.assignable#concept:assignable_from "18.4.8Concept assignable_­from[concept.assignable]")<S&, const S2&> constexpr common_iterator& operator=(const common_iterator<I2, S2>& x);

5

#

Hardened preconditions: x.v_.valueless_by_exception() is false.

6

#

Effects: Equivalent to:

  • (6.1)

    If v_.index() == x.v_.index(), thenget(v_) = get(x.v_).

  • (6.2)

    Otherwise, v_.emplace(get(x.v_)).

where i is x.v_.index().

7

#

Returns: *this.

24.5.5.4 Accessors [common.iter.access]

🔗

constexpr decltype(auto) operator*(); constexpr decltype(auto) operator*() const requires [dereferenceable](iterator.synopsis#concept:dereferenceable "24.2Header <iterator>&nbsp;synopsis[iterator.synopsis]")<const I>;

1

#

Hardened preconditions: holds_alternative(v_) is true.

2

#

Effects: Equivalent to: return *get(v_);

🔗

constexpr auto operator->() const requires see below;

3

#

The expression in the requires-clause is equivalent to:indirectly_readable &&(requires(const I& i) { i.operator->(); } || is_reference_v<iter_reference_t> ||constructible_from<iter_value_t, iter_reference_t>)

4

#

Hardened preconditions: holds_alternative(v_) is true.

5

#

Effects:

If I is a pointer type or if the expressionget(v_).operator->() is well-formed, equivalent to: return get(v_);

Otherwise, if iter_reference_t is a reference type, equivalent to:auto&& tmp = *get(v_);return addressof(tmp);

Otherwise, equivalent to:return proxy(get(v_)); whereproxy* is the exposition-only class:class proxy { iter_value_t keep_; constexpr proxy(iter_reference_t&& x): keep_(std::move(x)) {}public:constexpr const iter_value_t* operator->() const noexcept {return addressof(keep_); }};

24.5.5.5 Navigation [common.iter.nav]

🔗

constexpr common_iterator& operator++();

1

#

Hardened preconditions: holds_alternative(v_) is true.

2

#

Effects: Equivalent to ++get(v_).

3

#

Returns: *this.

🔗

constexpr decltype(auto) operator++(int);

4

#

Hardened preconditions: holds_alternative(v_) is true.

5

#

Effects: If I models forward_iterator, equivalent to:common_iterator tmp = *this;++*this;return tmp;

Otherwise, ifrequires(I& i) { { *i++ } -> can-reference; } is true orindirectly_readable && constructible_from<iter_value_t, iter_reference_t> &&move_constructible<iter_value_t> is false, equivalent to:return get(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 keep_; constexpr postfix-proxy(iter_reference_t&& x): keep_(std::forward<iter_reference_t>(x)) {}public:constexpr const iter_value_t& operator() const noexcept {return keep_; }};

24.5.5.6 Comparisons [common.iter.cmp]

🔗

template<class I2, [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept sentinel_­for[iterator.concept.sentinel]")<I> S2> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept sentinel_­for[iterator.concept.sentinel]")<S, I2> friend constexpr bool operator==( const common_iterator& x, const common_iterator<I2, S2>& y);

1

#

Hardened preconditions: x.v_.valueless_by_exception() and y.v_.valueless_by_exception() are each false.

2

#

Returns: true if i == j, and otherwise get(x.v_) == get(y.v_), where i is x.v_.index() and j is y.v_.index().

🔗

template<class I2, [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept sentinel_­for[iterator.concept.sentinel]")<I> S2> requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept sentinel_­for[iterator.concept.sentinel]")<S, I2> && [equality_comparable_with](concept.equalitycomparable#concept:equality_comparable_with "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<I, I2> friend constexpr bool operator==( const common_iterator& x, const common_iterator<I2, S2>& y);

3

#

Hardened preconditions: x.v_.valueless_by_exception() and y.v_.valueless_by_exception() are each false.

4

#

Returns: true if i and j are each 1, and otherwiseget(x.v_) == get(y.v_), wherei is x.v_.index() and j is y.v_.index().

🔗

template<[sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<I> I2, [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<I> S2> requires [sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<S, I2> friend constexpr iter_difference_t<I2> operator-( const common_iterator& x, const common_iterator<I2, S2>& y);

5

#

Hardened preconditions: x.v_.valueless_by_exception() and y.v_.valueless_by_exception() are each false.

6

#

Returns: 0 if i and j are each 1, and otherwiseget(x.v_) - get(y.v_), wherei 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](iterator.concept.input#concept:input_iterator "24.3.4.9Concept input_­iterator[iterator.concept.input]")<I>;

1

#

Hardened preconditions: holds_alternative(i.v_) is true.

2

#

Effects: Equivalent to: return ranges::iter_move(get(i.v_));

🔗

template<[indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<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&>())));

3

#

Hardened preconditions: holds_alternative(x.v_) and holds_alternative(y.v_) are each true.

4

#

Effects: Equivalent to ranges::iter_swap(get(x.v_), get(y.v_)).