table of contents
std::ranges::find_last,std::ranges::find_last_if,std::ranges::find_last_if_not(3) | C++ Standard Libary | std::ranges::find_last,std::ranges::find_last_if,std::ranges::find_last_if_not(3) |
NAME¶
std::ranges::find_last,std::ranges::find_last_if,std::ranges::find_last_if_not - std::ranges::find_last,std::ranges::find_last_if,std::ranges::find_last_if_not
Synopsis¶
Defined in header <algorithm>
Call signature
template< std::forward_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 ranges::subrange<I>
find_last( I first, S last, const T& value, Proj proj = {} );
template< std::forward_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 ranges::subrange<I>
find_last( I first, S last, const T& value, Proj proj = {} );
template< ranges::forward_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 ranges::borrowed_subrange_t<R>
find_last( R&& r, const T& value, Proj proj = {} );
template< ranges::forward_range R,
class Proj = std::identity,
class T = std::projected_value_t<iterator_t<R>, Proj> >
requires std::indirect_binary_predicate<ranges::equal_to, (since
C++26)
std::projected<ranges::iterator_t<R>, Proj>, (1)
const T*>
constexpr ranges::borrowed_subrange_t<R>
find_last( R&& r, const T& value, Proj proj = {} );
template< std::forward_iterator I, std::sentinel_for<I> S,
class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> (3)
(since
Pred > C++23)
constexpr ranges::subrange<I> (2)
find_last_if( I first, S last, Pred pred, Proj proj = {} );
template< ranges::forward_range R, class Proj = std::identity,
std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>,
(since
Proj>> (4) C++23)
Pred >
constexpr ranges::borrowed_subrange_t<R>
find_last_if( R&& r, Pred pred, Proj proj = {} );
template< std::forward_iterator I, std::sentinel_for<I> S,
class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> (5)
(since
Pred > C++23)
constexpr ranges::subrange<I>
find_last_if_not( I first, S last, Pred pred, Proj proj = {} );
template< ranges::forward_range R, class Proj = std::identity,
std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>,
(since
Proj>> (6) C++23)
Pred >
constexpr ranges::borrowed_subrange_t<R>
find_last_if_not( R&& r, Pred pred, Proj proj = {} );
Returns the last element in the range [first, last) that satisfies specific
criteria:
1) find_last searches for an element equal to value.
3) find_last_if searches for the last element in the range [first, last) for
which
predicate pred returns true.
5) find_last_if_not searches for the last element in the range [first, last)
for
which predicate pred returns false.
2,4,6) Same as (1,3,5), but uses r as the source range, as if using
ranges::begin(r)
as first and ranges::end(r) as last.
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 examine
r - the range of the elements to examine
value - value to compare the elements to
pred - predicate to apply to the projected elements
proj - projection to apply to the elements
Return value¶
1,2,3) Let i be the last iterator in the range [first, last) for
which E is true.
Returns ranges::subrange<I>{i, last}, or
ranges::subrange<I>{last, last} if no such
iterator is found.
2,4,6) Same as (1,2,3) but the return type is
ranges::borrowed_subrange_t<I>.
Complexity¶
At most last - first applications of the predicate and projection.
Notes¶
ranges::find_last, ranges::find_last_if, ranges::find_last_if_not
have better
efficiency on common implementations if I models bidirectional_iterator or
(better)
random_access_iterator.
Feature-test macro Value Std Feature
ranges::find_last,
__cpp_lib_ranges_find_last 202207L (C++23) ranges::find_last_if,
ranges::find_last_if_not
__cpp_lib_algorithm_default_value_type 202403 (C++26) List-initialization for
algorithms (1,2)
Possible implementation¶
These implementations only show the slower algorithm used when I
models
forward_iterator.
find_last (1-2)
struct find_last_fn
{
template<std::forward_iterator I, std::sentinel_for<I> S,
class Proj = std::identity,
class T = std::projected_value_t<iterator_t<R>, Proj>>
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 Proj = std::identity,
class T = std::projected_value_t<iterator_t<R>, Proj>>
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;
find_last_if (3-4)
struct find_last_if_fn
{
template<std::forward_iterator I, std::sentinel_for<I> S,
class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
constexpr ranges::subrange<I>
operator()(I first, S last, Pred pred, 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(pred, std::invoke(proj, *first)))
found = first;
if (found == I {})
return {first, first};
return {found, std::ranges::next(found, last)};
}
template<ranges::forward_range R, class Proj = std::identity,
std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>,
Proj>>
Pred>
constexpr ranges::borrowed_subrange_t<R>
operator()(R&& r, Pred pred, Proj proj = {}) const
{
return this->operator()(ranges::begin(r), ranges::end(r),
std::ref(pred), std::ref(proj));
}
};
inline constexpr find_last_if_fn find_last_if;
find_last_if_not (5-6)
struct find_last_if_not_fn
{
template<std::forward_iterator I, std::sentinel_for<I> S,
class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
constexpr ranges::subrange<I>
operator()(I first, S last, Pred pred, 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(pred, std::invoke(proj, *first)))
found = first;
if (found == I {})
return {first, first};
return {found, std::ranges::next(found, last)};
}
template<ranges::forward_range R, class Proj = std::identity,
std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>,
Proj>>
Pred>
constexpr ranges::borrowed_subrange_t<R>
operator()(R&& r, Pred pred, Proj proj = {}) const
{
return this->operator()(ranges::begin(r), ranges::end(r),
std::ref(pred), std::ref(proj));
}
};
inline constexpr find_last_if_not_fn find_last_if_not;
Example¶
// Run this code
#include <algorithm>
#include <cassert>
#include <forward_list>
#include <iomanip>
#include <iostream>
#include <string_view>
int main()
{
namespace ranges = std::ranges;
constexpr static auto v = {1, 2, 3, 1, 2, 3, 1, 2};
{
constexpr auto i1 = ranges::find_last(v.begin(), v.end(), 3);
constexpr auto i2 = ranges::find_last(v, 3);
static_assert(ranges::distance(v.begin(), i1.begin()) == 5);
static_assert(ranges::distance(v.begin(), i2.begin()) == 5);
}
{
constexpr auto i1 = ranges::find_last(v.begin(), v.end(), -3);
constexpr auto i2 = 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 = ranges::find_last_if(v.begin(), v.end(), pred, abs);
constexpr auto i2 = ranges::find_last_if(v, pred, abs);
static_assert(ranges::distance(v.begin(), i1.begin()) == 5);
static_assert(ranges::distance(v.begin(), i2.begin()) == 5);
}
{
auto pred = [](int x) { return x == -3; };
constexpr auto i1 = ranges::find_last_if(v.begin(), v.end(), pred, abs);
constexpr auto i2 = 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 = ranges::find_last_if_not(v.begin(), v.end(), pred, abs);
constexpr auto i2 = ranges::find_last_if_not(v, pred, abs);
static_assert(ranges::distance(v.begin(), i1.begin()) == 5);
static_assert(ranges::distance(v.begin(), i2.begin()) == 5);
}
{
auto pred = [](int x) { return x == 1 or x == 2 or x == 3; };
constexpr auto i1 = ranges::find_last_if_not(v.begin(), v.end(), pred, abs);
constexpr auto i2 = 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 = 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';
#if __cpp_lib_algorithm_default_value_type
const auto i3 = ranges::find_last(list, {"three", 3}); // (2) C++26
#else
const auto i3 = ranges::find_last(list, P{"three", 3}); // (2)
C++23
#endif
assert(i3.begin()->first == "three" &&
i3.begin()->second == 3);
}
Output:¶
{"one", 4} {"two", 5} {"three", 6}
See also¶
ranges::find_end finds the last sequence of elements in a certain
range
(C++20) (niebloid)
ranges::find
ranges::find_if
ranges::find_if_not finds the first element satisfying specific criteria
(C++20) (niebloid)
(C++20)
(C++20)
ranges::search searches for a range of elements
(C++20) (niebloid)
ranges::includes returns true if one sequence is a subsequence of another
(C++20) (niebloid)
ranges::binary_search determines if an element exists in a partially-ordered
(C++20) range
(niebloid)
ranges::contains
ranges::contains_subrange checks if the range contains the given element or
subrange
(C++23) (niebloid)
(C++23)
2024.06.10 | http://cppreference.com |