std::ranges...ns_subrange(3)
π NAME π
okay so this is the std::ranges...ns_subrange(3) page from the C++ Standard Libary manual β yes, the header spells it βLibary,β and Iβm keeping the typo because itβs iconic π.
The original NAME line is literally:
std::ranges::contains,std::ranges::contains_subrange - std::ranges::contains,std::ranges::contains_subrange
So yeah bestie, itβs about std::ranges::contains and std::ranges::contains_subrange. One checks βis this value in the range?β and the other checks βis this subrange inside the range?β β¨
πΈ Synopsis πΈ
Defined in header <algorithm>.
Call signature β the original is a little feral with line breaks, so hereβs the synopsis exactly as printed, no cap:
Defined in header <algorithm>
Call signature
template< std::input_iterator I, std::sentinel_for<I> S,
class T,
class Proj = std::identity >
(since
requires std::indirect_binary_predicate<ranges::equal_to,
C++23)
std::projected<I, Proj>,
(until
const T*>
C++26)
constexpr bool contains( I first, S last, const T& value,
Proj proj = {} );
template< std::input_iterator I, std::sentinel_for<I> S,
class Proj = std::identity,
class T = std::projected_value_t<I, Proj> >
requires std::indirect_binary_predicate<ranges::equal_to,
(since
std::projected<I, Proj>,
C++26)
const T*>
constexpr bool contains( I first, S last, const T& value,
Proj proj = {} );
template< ranges::input_range R,
class T,
class Proj = std::identity >
(since
requires std::indirect_binary_predicate<ranges::equal_to,
C++23)
(until
std::projected<ranges::iterator_t<R>, Proj>,
C++26)
const T*>
constexpr bool contains( R&& r, const T& value, Proj proj =
{} );
template< ranges::input_range R,
class Proj = std::identity,
class T =
std::projected_value_t<ranges::iterator_t<R>, Proj> >
requires std::indirect_binary_predicate<ranges::equal_to, (1)
(since
C++26)
std::projected<ranges::iterator_t<R>, Proj>,
const T*>
constexpr bool contains( R&& r, const T& value, Proj proj =
{} );
template< std::forward_iterator I1, std::sentinel_for<I1>
S1,
std::forward_iterator I2, std::sentinel_for<I2> (2)
S2,
class Pred = ranges::equal_to,
class Proj1 = std::identity, class Proj2 =
std::identity >
(3) (since
requires std::indirectly_comparable<I1, I2, Pred, Proj1,
C++23)
Proj2>
constexpr bool contains_subrange( I1 first1, S1 last1, I2
first2, S2 last2,
Pred pred = {},
Proj1 proj1 = {}, Proj2
proj2 = {} );
template< ranges::forward_range R1, ranges::forward_range
R2,
class Pred = ranges::equal_to,
class Proj1 = std::identity, class Proj2 =
std::identity >
requires std::indirectly_comparable<ranges::iterator_t<R1>,
(4) (since
ranges::iterator_t<R2>,
C++23)
Pred, Proj1, Proj2>
constexpr bool contains_subrange( R1&& r1, R2&& r2, Pred
pred = {},
Proj1 proj1 = {}, Proj2
proj2 = {} );
Hereβs what the numbered tea is:
- Search-based algorithm that checks whether or not a given range contains a value with iterator-sentinel pairs.
- Same as (1) but uses
ras the source range, as if usingranges::begin(r)asfirstandranges::end(r)aslast. - Search-based algorithm that checks whether or not a given range is a subrange of another range with iterator-sentinel pairs.
- Same as (3) but uses
r1as the first source range andr2as the second source range, as if usingranges::begin(r1)asfirst1,ranges::end(r1)aslast1,ranges::begin(r2)asfirst2, andranges::end(r2)aslast2.
The function-like entities described on this page are niebloids, that is:
- Explicit template argument lists cannot be specified when calling any of them.
- None of them are visible to argument-dependent lookup.
- When any of them are found by normal unqualified lookup as the name to the left of the function-call operator, argument-dependent lookup is inhibited.
In practice, they may be implemented as function objects, or with special compiler extensions.
π«Ά Parameters π«Ά
first,lastβ the range of elements to examinerβ the range of the elements to examinevalueβ value to compare the elements topredβ predicate to apply to the projected elementsprojβ projection to apply to the elements
β¨ Return value β¨
1,2):ranges::find(std::move(first), last, value, proj) != last3,4):first2 == last2 || !ranges::search(first1, last1, first2, last2, pred, proj1, proj2).empty()
β Complexity β
At most last - first applications of the predicate and projection.
π Notes π
Up until C++20, weβve had to write std::ranges::find(r, value) != std::ranges::end(r) to determine if a single value is inside a range. And to check if a range contains a subrange of interest, we use not std::ranges::search(haystack, needle).empty(). While this is accurate, it isnβt necessarily convenient, and it hardly expresses intent (especially in the latter case). Being able to say std::ranges::contains(r, value) addresses both of these points.
ranges::contains_subrange, same as ranges::search, but as opposed to std::search, provides no access to Searchers (such as Boyer-Moore).
Feature-test macro β hereβs the table tea, bestie:
__cpp_lib_ranges_containsβ value202207Lβ std(C++23)β feature:std::ranges::containsandranges::contains_subrange__cpp_lib_algorithm_default_value_typeβ value202403β std(C++26)β feature: List-initialization for algorithms(1,2)
π§ Possible implementation π§
contains (1,2)
struct __contains_fn
{
template<std::input_iterator I, std::sentinel_for<I> S,
class Proj = std::identity,
class T = std::projected_value_t<I, Proj>>
requires std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>,
const T*>
constexpr bool operator()(I first, S last, const T& value, Proj proj = {}) const
{
return ranges::find(std::move(first), last, value, proj) != last;
}
template<ranges::input_range R,
class Proj = std::identity,
class T = std::projected_value_t<ranges::iterator_t<R>, Proj>>
requires std::indirect_binary_predicate<ranges::equal_to,
std::projected<ranges::iterator_t<R>, Proj>,
const T*>
constexpr bool operator()(R&& r, const T& value, Proj proj = {}) const
{
return (*this)(ranges::begin(r), ranges::end(r), std::move(value), proj);
}
};
inline constexpr __contains_fn contains {};
contains_subrange (3,4)
struct __contains_subrange_fn
{
template<std::forward_iterator I1, std::sentinel_for<I1> S1,
std::forward_iterator I2, std::sentinel_for<I2> S2,
class Pred = ranges::equal_to,
class Proj1 = std::identity, class Proj2 = std::identity>
requires std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
constexpr bool operator()(I1 first1, S1 last1,
I2 first2, S2 last2,
Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {}) const
{
return (first2 == last2) ||
!ranges::search(first1, last1, first2, last2, pred, proj1, proj2).empty();
}
template<ranges::forward_range R1, ranges::forward_range R2,
class Pred = ranges::equal_to,
class Proj1 = std::identity, class Proj2 = std::identity>
requires std::indirectly_comparable<ranges::iterator_t<R1>,
ranges::iterator_t<R2>, Pred, Proj1, Proj2>
constexpr bool operator()(R1&& r1, R2&& r2,
Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {}) const
{
return (*this)(ranges::begin(r1), ranges::end(r1),
ranges::begin(r2), ranges::end(r2), std::move(pred),
std::move(proj1), std::move(proj2));
}
};
inline constexpr __contains_subrange_fn contains_subrange {};
π Example π
// Run this code
#include <algorithm>
#include <array>
#include <complex>
namespace ranges = std::ranges;
int main()
{
constexpr auto haystack = std::array{3, 1, 4, 1, 5};
constexpr auto needle = std::array{1, 4, 1};
constexpr auto bodkin = std::array{2, 5, 2};
static_assert(
ranges::contains(haystack, 4) &&
!ranges::contains(haystack, 6) &&
ranges::contains_subrange(haystack, needle) &&
!ranges::contains_subrange(haystack, bodkin)
);
constexpr std::array<std::complex<double>, 3> nums{{{1, 2}, {3, 4}, {5, 6}}};
#ifdef __cpp_lib_algorithm_default_value_type
static_assert(ranges::contains(nums, {3, 4}));
#else
static_assert(ranges::contains(nums, std::complex<double>{3, 4}));
#endif
}
π See also π
ranges::find,ranges::find_if,ranges::find_if_notβ finds the first element satisfying specific criteria. Original annotations:(C++20)(niebloid);(C++20);(C++20).ranges::searchβ searches for a range of elements.(C++20)(niebloid)ranges::binary_searchβ determines if an element exists in a partially-ordered range.(C++20)(niebloid)ranges::includesβ returns true if one sequence is a subsequence of another.(C++20)(niebloid)ranges::all_of,ranges::any_of,ranges::none_ofβ checks if a predicate is true for all, any or none of the elements in a range. Original annotations:(C++20)(niebloid);(C++20);(C++20).
thatβs the whole page, bestie π source: http://cppreference.com, version/date: 2024.06.10, footer title: std::ranges...ns_subrange(3). now go slay some ranges β¨π
π¦ 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