| Defined in header <algorithm>
|
||
| Call signature |
||
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>
find_last( I first, S last, const T& value, Proj proj = {} );
|
(1) | (since C++23) (until C++26) |
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, std::projected<I, Proj>, const T*>
constexpr ranges::subrange<I>
find_last( I first, S last, const T& value, Proj proj = {} );
|
(since C++26) | |
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>
find_last( R&& r, const T& value, Proj proj = {} );
|
(2) | (since C++23) (until C++26) |
template< ranges::forward_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 ranges::borrowed_subrange_t<R>
find_last( R&& r, const T& value, Proj proj = {} );
|
(since C++26) | |
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>
find_last_if( I first, S last, Pred pred, Proj proj = {} );
|
(3) | (since C++23) |
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>
find_last_if( R&& r, Pred pred, Proj proj = {} );
|
(4) | (since C++23) |
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>
find_last_if_not( I first, S last, Pred pred, Proj proj = {} );
|
(5) | (since C++23) |
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>
find_last_if_not( R&& r, Pred pred, Proj proj = {} );
|
(6) | (since C++23) |
template< /*execution-policy*/ Ep,
std::random_access_iterator I, std::sized_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*>
ranges::subrange<I> find_last( Ep&& policy, I first, S last,
const T& value, Proj proj = {} );
|
(7) | (since C++26) |
template< /*execution-policy*/ Ep, /*sized-random-access-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*>
ranges::borrowed_subrange_t<R>
find_last( Ep&& policy, R&& r, const T& value, Proj proj = {} );
|
(8) | (since C++26) |
template< /*execution-policy*/ Ep,
std::random_access_iterator I, std::sized_sentinel_for<I> S,
class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
ranges::subrange<I> find_last_if( Ep&& policy, I first, S last,
Pred pred, Proj proj = {} );
|
(9) | (since C++26) |
template< /*execution-policy*/ Ep, /*sized-random-access-range*/ R,
class Proj = std::identity,
std::indirect_unary_predicate
<std::projected<ranges::iterator_t<R>, Proj>> Pred >
ranges::borrowed_subrange_t<R>
find_last_if( Ep&& policy, R&& r, Pred pred, Proj proj = {} );
|
(10) | (since C++26) |
template< /*execution-policy*/ Ep,
std::random_access_iterator I, std::sized_sentinel_for<I> S,
class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
ranges::subrange<I> find_last_if_not( Ep&& policy, I first, S last,
Pred pred, Proj proj = {} );
|
(11) | (since C++26) |
template< /*execution-policy*/ Ep, /*sized-random-access-range*/ R,
class Proj = std::identity,
std::indirect_unary_predicate
<std::projected<ranges::iterator_t<R>, Proj>> Pred >
ranges::borrowed_subrange_t<R>
find_last_if_not( Ep&& policy, R&& r, Pred pred, Proj proj = {} );
|
(12) | (since C++26) |
For the definition of /*execution-policy*/, see this page; for the definition of /*sized-random-access-range*/, see this page.
Returns the last element (projected by proj) in the source range [first, last) or r that satisfies specific criteria:
find_last searches for the last element equal to value.find_last_if searches for the last element for which predicate pred returns true.find_last_if_not searches for the last element for which predicate pred returns false.policy.The function-like entities described on this page are algorithm function objects (informally known as 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.
Parameters
| first, last | - | the iterator-sentinel pair defining the source range |
| r | - | the source range |
| value | - | the target value |
| pred | - | the predicate to be applied to the (projected) elements |
| proj | - | the projection to be applied to the elements |
| policy | - | the execution policy to use |
Return value
A subrange from the last element satisfying the condition to the end of the source range, or an empty range if no such element is found.
Complexity
Given \(\scriptsize N\)N as ranges::distance(first, last) or ranges::distance(r):
proj.pred and proj.proj.pred and proj.Exceptions
- If the temporary memory resources required for parallelization are not available, std::bad_alloc is thrown.
- If an uncaught exception is thrown while accessing objects via an algorithm argument, the behavior is determined by the execution policy (for standard policies, std::terminate is invoked).
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 |
|---|---|---|---|
__cpp_lib_ranges_find_last |
202207L |
(C++23) | ranges::find_last,ranges::find_last_if,ranges::find_last_if_not
|
__cpp_lib_algorithm_default_value_type |
202403L |
(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 |
|---|
struct find_last_fn
{
template<std::forward_iterator I, std::sentinel_for<I> S,
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<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.
std::optional<I> found;
for (; first != last; ++first)
if (std::invoke(proj, *first) == value)
found = first;
if (!found)
return {first, first};
return {*found, 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)(ranges::begin(r),
ranges::next(ranges::begin(r), ranges::end(r)),
value, std::ref(proj));
}
};
inline constexpr find_last_fn find_last;
|
| find_last_if |
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.
std::optional<I> found;
for (; first != last; ++first)
if (std::invoke(pred, std::invoke(proj, *first)))
found = first;
if (!found)
return {first, first};
return {*found, 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)(ranges::begin(r),
ranges::next(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 |
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.
std::optional<I> found;
for (; first != last; ++first)
if (!std::invoke(pred, std::invoke(proj, *first)))
found = first;
if (!found)
return {first, first};
return {*found, 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)(ranges::begin(r),
ranges::next(ranges::begin(r), ranges::end(r)),
std::ref(pred), std::ref(proj));
}
};
inline constexpr find_last_if_not_fn find_last_if_not;
|
Example
#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);
std::cout << "The found element and the tail after it are:\n";
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:
The found element and the tail after it are:
{"one", 4} {"two", 5} {"three", 6}
See also
(C++20) |
finds the last sequence of elements in a certain range (algorithm function object) |
(C++20)(C++20)(C++20) |
finds the first element satisfying specific criteria (algorithm function object) |
(C++20) |
searches for the first occurrence of a range of elements (algorithm function object) |
(C++20) |
determines if one sequence is a subsequence of another (algorithm function object) |
(C++20) |
determines if an element exists in a range using binary search (algorithm function object) |
(C++23)(C++23) |
checks if the range contains the given element or subrange (algorithm function object) |