std::ranges...atorPairLike(3)
π std::ranges...atorPairLike(3) π
okay so this page lives in the C++ Standard Libary manual (yes, thatβs literally how the header spells it, bestie β weβre keeping the typo, itβs part of the lore π
). The page is for std::ranges::subrange::operatorPairLike, and the header is so iconic it says std::ranges::subrange::operatorPairLike twice. No cap.
β¨ NAME β¨
std::ranges::subrange::operatorPairLike β std::ranges::subrange::operatorPairLike
Itβs giving βconversion operator that turns a subrange into a pair-like type.β Obsessed. π¦
π«Ά Synopsis π«Ά
template< /* see below */ PairLike >
requires pair-like-convertible-from<PairLike, const I&, const S&>
constexpr operator PairLike() const;
Thatβs item (1), and itβs (since C++20). Slay. β¨
π§ Helper concepts π§
Item (2) is the exposition-only concept pair-like, (until C++23):
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>,
std::integral_constant<std::size_t, 2>>; // (until C++23)
typename std::tuple_element_t<0, 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>&>;
};
Then thereβs the (until C++23) version of pair-like-convertible-from β also (exposition only*):
template< class T, class U, class V >
concept pair-like-convertible-from =
!ranges::range<T> && pair-like<T> &&
std::constructible_from<T, U, V> &&
convertible-to-non-slicing<U, std::tuple_element_t<0, T>> &&
std::convertible_to<V, std::tuple_element_t<1, T>>;
And item (3) is the (since C++23) version, also (exposition only*). Note the extra !std::is_reference_v<T>, bestie:
template< class T, class U, class V >
concept pair-like-convertible-from =
!ranges::range<T> && !std::is_reference_v<T> && pair-like<T> &&
std::constructible_from<T, U, V> &&
convertible-to-non-slicing<U, std::tuple_element_t<0, T>> &&
std::convertible_to<V, std::tuple_element_t<1, T>>;
Now the numbered lore drop, same details, cuter delivery:
- Converts
subrangeto a pair-like type (i.e. a type models the helper conceptpair-likedefined below(until C++23)/pair-like(since C++23)). Equivalent toreturn PairLike(i_, s_);, wherei_ands_are the stored iterator and sentinel respectively.PairLikeis constrained thatstd::same_as<std::remove_cvref_t<PairLike>, subrange>is false. This conversion function has additional constraints imposed bypair-like-convertible(see below). - The exposition-only concept
pair-likespecifies a type is pair-like. Generally, an expressioneof 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 conceptpair-like(since C++23). - The exposition-only concept
pair-like-convertible-fromrefinespair-like. It:- rejects reference types and
(since C++23)range types, - requires that
UandVare convertible to the first and second element type ofTrespectively, and - requires the conversion from
U(which will be replaced byconst I&) to the first element type to be non-slicing (seeconvertible-to-non-slicing).
- rejects reference types and
πΈ Parameters πΈ
(none)
Literally no parameters. She said βIβm booked and busy.β π
π Return value π
A PairLike value direct-initialized with the stored iterator and sentinel. Periodt. π
π¦ 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_sizeandstd::tuple_elementare correctly specialized(until C++23)for it, and- calls to
std::get<0>andstd::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.
bestie, that last bit is the vibe check: range types stay in their lane for this conversion. π«Ά
β 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
Later, bestie! π
This iconic page says source http://cppreference.com, version/date 2024.06.10, and page std::ranges...atorPairLike(3). Slay and goodbye. π«Άβ¨
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms