std::ranges::find() algorithm
- since C++20
- Simplified
- Detailed
// (1)
constexpr I
find( I first, S last, const T& value, Proj proj = {} );
// (2)
constexpr ranges::borrowed_iterator_t<R>
find( R&& r, const T& value, Proj proj = {} );
The type of arguments are generic and have the following constraints:
I
-std::input_iterator
S
-std::sentinel_for<I>
T
- (none)Proj
- (none)- (2) -
R
-std::ranges::input_range
The Proj
template argument has a default type of std::identity
for all overloads.
Additionally, each overload has the following constraints:
- (1) -
indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>>
- (2) -
indirect_binary_predicate<ranges::equal_to, projected<ranges::iterator_t<R>, Proj>, const T*>
(The std::
namespace was ommitted here for readability)
// (1)
template<
std::input_iterator I,
std::sentinel_for<I> S,
class T,
class Proj = std::identity
>
requires std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>,
const T*>
constexpr I
find( I first, S last, const T& value, Proj proj = {} );
// (2)
template<
ranges::input_range R,
class T,
class Proj = std::identity
>
requires std::indirect_binary_predicate<ranges::equal_to,
std::projected<ranges::iterator_t<R>, Proj>,
const T*>
constexpr ranges::borrowed_iterator_t<R>
find( R&& r, const T& value, Proj proj = {} );
Returns the last element in the range [first
; last
) that satisfies specific criteria:
-
(1) Searches for an element equal to
value
(usingoperator==
) -
(2) Same as (1), but uses
r
as the source range, as if usingranges::begin(r)
asfirst
andranges::end(r)
aslast
.
The function-like entities described on this page are niebloids.
Parameters
first last | The range of elements to apply the function to. |
r | The range of elements to apply the function to. |
value | Value to compare the elements too. |
proj | Projection to apply to the elements. |
Return value
-
(1) Let
i
be the last iterator in the range [first
;last
) for which*i == value
istrue
. Returns a value of typeranges::subrange<I>
initialized as follows:{
i,
last
}or
{ last, last }
if no such iterator is found. -
(2) Same as (1) but the return type is
ranges::borrowed_subrange_t<I>
.
Complexity
Exactly last - first
applications of the predicate and projection.
Exceptions
(none)
Possible implementation
These implementations only show the slower algorithm used when I
models forward_iterator
.
find(1) and find(2)
struct find_last_fn
{
template<std::forward_iterator I, std::sentinel_for<I> S,
class T, class Proj = std::identity>
requires std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>,
const T*>
constexpr ranges::subrange<I>
operator()(I first, S last, const T &value, Proj proj = {}) const
{
// Note: if I is mere forward_iterator, we may only go from begin to end.
I found {};
for (; first != last; ++first)
if (std::invoke(proj, *first) == value)
found = first;
if (found == I {})
return {first, first};
return {found, std::ranges::next(found, last)};
}
template<ranges::forward_range R, class T, class Proj = std::identity>
requires std::indirect_binary_predicate<ranges::equal_to,
std::projected<ranges::iterator_t<R>, Proj>,
const T*>
constexpr ranges::borrowed_subrange_t<R>
operator()(R&& r, const T &value, Proj proj = {}) const
{
return this->operator()(ranges::begin(r), ranges::end(r), value, std::ref(proj));
}
};
inline constexpr find_last_fn find_last;
Notes
ranges::find_last
has better efficiency on common implementations if I
models bidirectional_iterator
or (better) random_access_iterator
.
Examples
#include <algorithm>
#include <forward_list>
#include <iomanip>
#include <iostream>
#include <string_view>
int main()
{
constexpr static auto v = {1, 2, 3, 1, 2, 3, 1, 2};
{
constexpr auto i1 = std::ranges::find_last(v.begin(), v.end(), 3);
constexpr auto i2 = std::ranges::find_last(v, 3);
static_assert(std::ranges::distance(v.begin(), i1.begin()) == 5);
static_assert(std::ranges::distance(v.begin(), i2.begin()) == 5);
}
{
constexpr auto i1 = std::ranges::find_last(v.begin(), v.end(), -3);
constexpr auto i2 = std::ranges::find_last(v, -3);
static_assert(i1.begin() == v.end());
static_assert(i2.begin() == v.end());
}
auto abs = [](int x) { return x < 0 ? -x : x; };
{
auto pred = [](int x) { return x == 3; };
constexpr auto i1 = std::ranges::find_last_if(v.begin(), v.end(), pred, abs);
constexpr auto i2 = std::ranges::find_last_if(v, pred, abs);
static_assert(std::ranges::distance(v.begin(), i1.begin()) == 5);
static_assert(std::ranges::distance(v.begin(), i2.begin()) == 5);
}
{
auto pred = [](int x) { return x == -3; };
constexpr auto i1 = std::ranges::find_last_if(v.begin(), v.end(), pred, abs);
constexpr auto i2 = std::ranges::find_last_if(v, pred, abs);
static_assert(i1.begin() == v.end());
static_assert(i2.begin() == v.end());
}
{
auto pred = [](int x) { return x == 1 or x == 2; };
constexpr auto i1 = std::ranges::find_last_if_not(v.begin(), v.end(), pred, abs);
constexpr auto i2 = std::ranges::find_last_if_not(v, pred, abs);
static_assert(std::ranges::distance(v.begin(), i1.begin()) == 5);
static_assert(std::ranges::distance(v.begin(), i2.begin()) == 5);
}
{
auto pred = [](int x) { return x == 1 or x == 2 or x == 3; };
constexpr auto i1 = std::ranges::find_last_if_not(v.begin(), v.end(), pred, abs);
constexpr auto i2 = std::ranges::find_last_if_not(v, pred, abs);
static_assert(i1.begin() == v.end());
static_assert(i2.begin() == v.end());
}
using P = std::pair<std::string_view, int>;
std::forward_list<P> list
{
{"one", 1}, {"two", 2}, {"three", 3},
{"one", 4}, {"two", 5}, {"three", 6},
};
auto cmp_one = [](const std::string_view &s) { return s == "one"; };
// find latest element that satisfy the comparator, and projecting pair::first
const auto subrange = std::ranges::find_last_if(list, cmp_one, &P::first);
// print the found element and the "tail" after it
for (P const& e : subrange)
std::cout << '{' << std::quoted(e.first) << ", " << e.second << "} ";
std::cout << '\n';
}
{"one", 4} {"two", 5} {"three", 6}
Hover to see the original license.