std::ranges::subrange::operatorPairLike(3)

NAME
std::ranges::subrange::operatorPairLike - std::ranges::subrange::operatorPairLike

Synopsis
   template< /* see below */ PairLike >
       requires pair-like-convertible-from<PairLike, (1) (since C++20)
   const I&, const S&>
   constexpr operator PairLike() const;
   Helper concepts
   template< class T >
   concept pair-like =
       !std::is_reference_v<T> && requires(T t) {
           typename std::tuple_size<T>::type; //
   ensures std::tuple_size<T>
                        // is
   complete
           requires
   std::derived_from<std::tuple_size<T>,
                        (until C++23)
    std::integral_constant<std::size_t, 2>>; (2) (exposition
           typename std::tuple_element_t<0, only*)
   std::remove_const_t<T>>;
           typename std::tuple_element_t<1,
   std::remove_const_t<T>>;
           { std::get<0>(t) } -> std::convertible_to<
                        const
   std::tuple_element_t<0, T>&>;
           { std::get<1>(t) } -> std::convertible_to<
                        const
   std::tuple_element_t<1, T>&>;
       };
   template< class T, class U, class V >
   concept pair-like-convertible-from =
       !ranges::range<T> && pair-like<T> && (until C++23)
       std::constructible_from<T, U, V> && (exposition
       convertible-to-non-slicing<U, only*)
   std::tuple_element_t<0, T>> &&
       std::convertible_to<V, std::tuple_element_t<1,
   T>>;
   template< class T, class U, class V > (3)
   concept pair-like-convertible-from =
       !ranges::range<T> && !std::is_reference_v<T>
   && pair-like<T> && (since C++23)
       std::constructible_from<T, U, V> && (exposition
       convertible-to-non-slicing<U, only*)
   std::tuple_element_t<0, T>> &&
       std::convertible_to<V, std::tuple_element_t<1,
   T>>;
   1) Converts subrange to a pair-like type (i.e. a type models
   the helper concept pair-like defined below
   (until C++23)
   pair-like
   (since C++23)). Equivalent to return PairLike(i_, s_);, where i_ and s_ are the
   stored iterator and sentinel respectively.
   PairLike is constrained that std::same_as<std::remove_cvref_t<PairLike>, subrange>
   is false.
   This conversion function has additional constraints imposed by pair-like-convertible
   (see below).
   2) The exposition-only concept pair-like specifies a type is pair-like. Generally,
   an expression e of a pair-like type can be used for structured binding (i.e. auto
   const& [x, y] = e; is generally well-formed).
   This concept is replaced by the library-wide exposition-only concept pair-like.
   (since C++23)
   3) The exposition-only concept pair-like-convertible-from refines pair-like. It
     * rejects
       reference types and
       (since C++23)range types,
     * requires that U and V are convertible to the first and second element type of T
       respectively, and
     * requires the conversion from U (which will be replaced by const I&) to the first
       element type to be non-slicing (see convertible-to-non-slicing).

Parameters
   (none)

Return value
   A PairLike value direct-initialized with the stored iterator and sentinel.

Notes
   Following types in the standard library are pair-like:
     * std::pair<T, U>
     * std::tuple<T, U>
     * std::array<T, 2>
     * std::ranges::subrange<I, S, K>
     * std::complex<T> (since C++26)
   A program-defined type derived from one of these types can be a
   pair-like type, if
     * std::tuple_size and std::tuple_element are correctly specialized (until C++23)
       for it, and
     * calls to std::get<0> and std::get<1> for its value are
       well-formed.
   Since subrange specializations are range types, conversion to them are not performed
   via this conversion function.
   std::array specializations cannot be converted from subrange, since they are range
   types.

Example
// Run this code
 #include <iostream>
 #include <ranges>
 #include <string>
 #include <utility>
 using striter = std::string::const_iterator;
 using legacy_strview = std::pair<striter, striter>;
 void legacy_print(legacy_strview p)
 {
     for (; p.first != p.second; ++p.first)
         std::cout << *p.first << ' ';
     std::cout << '\n';
 }
 int main()
 {
     std::string dat{"ABCDE"};
     for (auto v{std::ranges::subrange{dat}}; v; v = {v.begin(), v.end() - 1})
     {
         /*...*/
         legacy_print(legacy_strview{v});
     }
 }

Output:
 A B C D E
 A B C D
 A B C
 A B
 A