Skip to main content

std::ranges::find_last_if() algorithm

// (1)
constexpr ranges::subrange<I>
find_last_if( I first, S last, Pred pred, Proj proj = {} );

// (2)
constexpr ranges::borrowed_subrange_t<R>
find_last_if( R&& r, Pred pred, Proj proj = {} );

The type of arguments are generic and have the following constraints:

  • I - std::input_iterator
  • S - std::sentinel_for<I>
  • Proj - (none)
  • Pred:
    • (1) - std::indirect_unary_predicate<std::projected<I, Proj>>
    • (2) - std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>>
  • (2) - R - std::ranges::input_range

The Proj template argument has a default type of std::identity for all overloads.

Returns the last element in the range [first; last) that satisfies specific criteria:

  • (1) Searches for an element for which predicate pred returns true.

  • (2) Same as (1), 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.

Parameters

first
last

The range of elements to examine.

r

The range of elements to examine.

pred

Predicate to apply to the projected elements.

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 is true. Returns a value of type ranges::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

At most last - first applications of the predicate and projection.

Exceptions

(none)

Possible implementation

find_last_if(1)
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;

Examples

Main.cpp
#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';
}
Output
{"one", 4} {"two", 5} {"three", 6}
This article originates from this CppReference page. It was likely altered for improvements or editors' preference. Click "Edit this page" to see all changes made to this document.
Hover to see the original license.

std::ranges::find_last_if() algorithm

// (1)
constexpr ranges::subrange<I>
find_last_if( I first, S last, Pred pred, Proj proj = {} );

// (2)
constexpr ranges::borrowed_subrange_t<R>
find_last_if( R&& r, Pred pred, Proj proj = {} );

The type of arguments are generic and have the following constraints:

  • I - std::input_iterator
  • S - std::sentinel_for<I>
  • Proj - (none)
  • Pred:
    • (1) - std::indirect_unary_predicate<std::projected<I, Proj>>
    • (2) - std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>>
  • (2) - R - std::ranges::input_range

The Proj template argument has a default type of std::identity for all overloads.

Returns the last element in the range [first; last) that satisfies specific criteria:

  • (1) Searches for an element for which predicate pred returns true.

  • (2) Same as (1), 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.

Parameters

first
last

The range of elements to examine.

r

The range of elements to examine.

pred

Predicate to apply to the projected elements.

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 is true. Returns a value of type ranges::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

At most last - first applications of the predicate and projection.

Exceptions

(none)

Possible implementation

find_last_if(1)
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;

Examples

Main.cpp
#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';
}
Output
{"one", 4} {"two", 5} {"three", 6}
This article originates from this CppReference page. It was likely altered for improvements or editors' preference. Click "Edit this page" to see all changes made to this document.
Hover to see the original license.