std::ranges::includes(3)
π
std::ranges::includes β the <algorithm> bestie you didn't know you needed
okay so this one lives in the C++ Standard Library's <algorithm> header and honestly? it's giving "does this fit inside that" energy. it's std::ranges::includes, and yes it's a niebloid (we'll get to that, don't worry π«Ά).
β¨ NAME β¨
std::ranges::includes β literally just std::ranges::includes, no notes, that's the whole name bestie π
πΈ SYNOPSIS πΈ
Defined in header <algorithm>. Call signature goes a lil something like this:
template< std::input_iterator I1, std::sentinel_for<I1> S1,
std::input_iterator I2, std::sentinel_for<I2> S2,
class Proj1 = std::identity, class Proj2 = std::identity,
std::indirect_strict_weak_order<
std::projected<I1, Proj1>,
std::projected<I2, Proj2>> Comp = ranges::less >
(1) (since C++20)
constexpr bool
includes( I1 first1, S1 last1, I2 first2, S2 last2,
Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {} )
template< ranges::input_range R1, ranges::input_range R2,
class Proj1 = std::identity, class Proj2 = std::identity,
std::indirect_strict_weak_order<
std::projected<ranges::iterator_t<R1>, Proj1>,
std::projected<ranges::iterator_t<R2>, Proj2>> Comp = ranges::less >
(2) (since C++20)
constexpr bool
includes( R1&& r1, R2&& r2, Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {} )
- Returns
trueif the projections of the sorted range[first2, last2)is a subsequence of the projections of the sorted range[first1, last1). - Same as (1), but uses
r1andr2as the source ranges, as if by usingranges::begin(r1)andranges::begin(r2)as first1 and first2 respectively, andranges::end(r1)andranges::end(r2)as last1 and last2 respectively.
π¦ DESCRIPTION π¦
so. both ranges must be sorted with the given comparison function comp. no cap, that's non-negotiable β the whole algorithm hinges on it. and a subsequence doesn't have to be contiguous, which is lowkey the best part: {a, c} totally counts as a subsequence of {a, b, c} because the b is just... vibing in between, iykyk.
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. main character energy either way π
π PARAMETERS π
first1,last1β the sorted range of elements to examiner1β the sorted range of elements to examinefirst2,last2β the sorted range of elements to search forr2β the sorted range of elements to search forcompβ comparison function to apply to the projected elementsproj1β projection to apply to the elements in the first rangeproj2β projection to apply to the elements in the second range
β RETURN VALUE β
true if [first2, last2) is a subsequence of [first1, last1); otherwise false. iconic binary behavior, we love to see it π
π₯ COMPLEXITY π₯
at most 2Β·(N1+N2β1) comparisons, where N1 is ranges::distance(r1) and N2 is ranges::distance(r2). not too shabby, not too spicy πΆοΈ
π§ POSSIBLE IMPLEMENTATION π§
for the girlies who need to see the source, here's how it could go:
struct includes_fn
{
template<std::input_iterator I1, std::sentinel_for<I1> S1,
std::input_iterator I2, std::sentinel_for<I2> S2,
class Proj1 = std::identity, class Proj2 = std::identity,
std::indirect_strict_weak_order<
std::projected<I1, Proj1>,
std::projected<I2, Proj2>> Comp = ranges::less>
constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2,
Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const
{
for (; first2 != last2; ++first1)
{
if (first1 == last1 || comp(*first2, *first1))
return false;
if (!comp(*first1, *first2))
++first2;
}
return true;
}
template<ranges::input_range R1, ranges::input_range R2,
class Proj1 = std::identity, class Proj2 = std::identity,
std::indirect_strict_weak_order<
std::projected<ranges::iterator_t<R1>, Proj1>,
std::projected<ranges::iterator_t<R2>, Proj2>> Comp = ranges::less>
constexpr bool operator()(R1&& r1, R2&& r2, Comp comp = {},
Proj1 proj1 = {}, Proj2 proj2 = {}) const
{
return (*this)(ranges::begin(r1), ranges::end(r1),
ranges::begin(r2), ranges::end(r2),
std::ref(comp), std::ref(proj1), std::ref(proj2));
}
};
inline constexpr auto includes = includes_fn {};
look at that inline constexpr auto includes = includes_fn {}; β periodt. π
π EXAMPLE π
// Run this code
#include <algorithm>
#include <cctype>
#include <initializer_list>
#include <iomanip>
#include <iostream>
#include <locale>
#include <string>
template<class T>
std::ostream& operator<<(std::ostream& os, std::initializer_list<T> const& list)
{
for (os << "{ "; auto const& elem : list)
os << elem << ' ';
return os << "} ";
}
struct true_false : std::numpunct<char>
{
std::string do_truename() const { return "? Yes\n"; }
std::string do_falsename() const { return "? No\n"; }
};
int main()
{
std::cout.imbue(std::locale(std::cout.getloc(), new true_false));
auto ignore_case = [](char a, char b) { return std::tolower(a) < std::tolower(b); };
const auto
a = {'a', 'b', 'c'},
b = {'a', 'c'},
c = {'a', 'a', 'b'},
d = {'g'},
e = {'a', 'c', 'g'},
f = {'A', 'B', 'C'},
z = {'a', 'b', 'c', 'f', 'h', 'x'};
std::cout
<< z << "includes\n" << std::boolalpha
<< a << std::ranges::includes(z.begin(), z.end(), a.begin(), a.end())
<< b << std::ranges::includes(z, b)
<< c << std::ranges::includes(z, c)
<< d << std::ranges::includes(z, d)
<< e << std::ranges::includes(z, e)
<< f << std::ranges::includes(z, f, ignore_case);
}
β¨ Output β¨
{ a b c f h x } includes
{ a b c } ? Yes
{ a c } ? Yes
{ a a b } ? No
{ g } ? No
{ a c g } ? No
{ A B C } ? Yes
not the { a a b } ? No catching people off guard π yeah bestie, the second range has two as and the first only has one β subsequence rules are strict like that. and the last one slays because of the custom ignore_case comparator, we love a case-insensitive queen π
π SEE ALSO π
ranges::set_difference(C++20) β computes the difference between two sets (niebloid)ranges::search(C++20) β searches for a range of elements (niebloid)ranges::contains(C++23) /ranges::contains_subrange(C++23) β checks if the range contains the given element or subrange (niebloid)includesβ returnstrueif one sequence is a subsequence of another (function template)
okay that's the whole page, go forth and check your subsequences π¦π
source:http://cppreference.com, dated2024.06.10, from thestd::ranges::includes(3)page. mwah, stan cppreference for me π β¨
π¦ 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