Namespaces
Variants

std::ranges::find_last, std::ranges::find_last_if, std::ranges::find_last_if_not

С сайта ru.cppreference.net
 
 
Библиотека алгоритмов
Ограниченные алгоритмы и алгоритмы на диапазонах (C++20)
Ограниченные алгоритмы, например ranges::copy, ranges::sort, ...
Немодифицирующие операции с последовательностями    
Пакетные операции
(C++17)
Операции поиска
Модифицирующие операции с последовательностями
Операции копирования
(C++11)
(C++11)
Операции обмена
Операции преобразования
Операции генерации
Операции удаления
Операции изменения порядка
(до C++17)(C++11)
(C++20)(C++20)
Операции выборки
(C++17)

Сортировка и связанные операции
Операции разбиения
(C++11)    

Операции сортировки
Операции двоичного поиска
(на разбитых диапазонах)
Операции над множествами (на отсортированных диапазонах)
Операции слияния (на отсортированных диапазонах)
Операции с кучей
Операции минимума/максимума
(C++11)
(C++17)
Операции лексикографического сравнения
Операции перестановок


Политики выполнения (C++17)
(только для пояснения*)(C++26)

Численные операции
(C++11)
(C++17)
(C++17)    

Специализированные <memory> алгоритмы

Специализированные <random> алгоритмы
Библиотека C









 
Ограниченные алгоритмы
Все имена в этом меню принадлежат пространству имён std::ranges
Немодифицирующие операции с последовательностями
Модифицирующие операции с последовательностями
Операции разбиения
Операции сортировки
Операции двоичного поиска (на отсортированных диапазонах)
       
       
Операции над множествами (на отсортированных диапазонах)
Операции с кучей
Операции минимума/максимума
       
       
Операции перестановок
Операции свёртки
Операции над неинициализированной памятью
Типы возврата
 
Определено в заголовке <algorithm>
Сигнатура вызова
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) (начиная с C++23)
(до 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 = {} );
(начиная с 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) (начиная с C++23)
(до 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 = {} );
(начиная с 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) (начиная с 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) (начиная с 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) (начиная с 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) (начиная с 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) (начиная с 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) (начиная с 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) (начиная с 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) (начиная с 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) (начиная с 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) (начиная с C++26)

Определение /*execution-policy*/ см. на этой странице; определение /*sized-random-access-range*/ см. на этой странице.

Возвращает последний элемент (спроецированный с помощью proj) в исходном диапазоне [first, last) или r, удовлетворяющий определённым критериям:

1,2) find_last ищет последний элемент, равный value.
3,4) find_last_if ищет последний элемент, для которого предикат pred возвращает true.
5,6) find_last_if_not ищет последний элемент, для которого предикат pred возвращает false.
7-12) То же, что и (1-6), но выполняется в соответствии с policy.

Функциональные объекты, описанные на этой странице, являются объектами-функциями алгоритмов (неформально известными как niebloids), то есть:

Параметры

first, last - пара итератор-страж, определяющая исходный диапазон
r - исходный диапазон
value - целевое значение
pred - предикат, применяемый к (проецированным) элементам
proj - проекция, применяемая к элементам
policy - используемая политика выполнения для использования

Возвращаемое значение

Поддиапазон от последнего элемента, удовлетворяющего условию, до конца исходного диапазона, или пустой диапазон, если такой элемент не найден.

Сложность

Дано N как ranges::distance(first, last) или ranges::distance(r):

1,2) Не более N сравнений и применений proj.
3-6) Не более N применений pred и proj.
7,8) 𝓞(N) сравнений и применений proj.
9-12) 𝓞(N) применений pred и proj.

Исключения

7-12) В процессе выполнения:
  • Если временные ресурсы памяти, необходимые для распараллеливания, недоступны, std::bad_alloc выбрасывается.
  • Если необработанное исключение выбрасывается при доступе к объектам через аргумент алгоритма, поведение определяется политикой выполнения (для стандартных политик, std::terminate вызывается).

Примечания

ranges::find_last , ranges::find_last_if , ranges::find_last_if_not обладают лучшей эффективностью в распространённых реализациях, если I моделирует bidirectional_iterator или (предпочтительно) random_access_iterator .

Макрос тестирования возможностей Значение Стандарт Функция
__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) Списковая инициализация для алгоритмов ( 1,2 )

Возможная реализация

Эти реализации показывают только медленный алгоритм, используемый, когда I является моделью 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;

Пример

#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
    {
        {"один", 1}, {"два", 2}, {"три", 3},
        {"один", 4}, {"два", 5}, {"три", 6},
    };
    auto cmp_one = [](const std::string_view &s) { return s == "один"; };
    // найти последний элемент, удовлетворяющий компаратору, с проекцией pair::first
    const auto subrange = ranges::find_last_if(list, cmp_one, &P::первый);
    std::cout << "Найденный элемент и хвост после него:\n";
    for (P const& e : subrange)
        std::cout << '{' << std::quoted(e.первый) << ", " << e.second << "} ";
    std::cout << '\n';
#if __cpp_lib_algorithm_default_value_type
    const auto i3 = ranges::find_last(list, {"три", 3}); // (2) C++26
#else
    const auto i3 = ranges::find_last(list, P{"три", 3}); // (2) C++23
#endif
    assert(i3.begin()->first == "три" && i3.begin()->second == 3);
}

Вывод:

Найденный элемент и хвост после него:
{"one", 4} {"two", 5} {"three", 6}

См. также

находит последнюю последовательность элементов в определённом диапазоне
(объект функции алгоритма)
находит первый элемент, удовлетворяющий определённым критериям
(объект функции алгоритма)
ищет первое вхождение диапазона элементов
(объект функции алгоритма)
определяет, является ли одна последовательность подпоследовательностью другой
(объект функции алгоритма)
определяет наличие элемента в диапазоне с помощью бинарного поиска
(объект функции алгоритма)
проверяет, содержит ли диапазон данный элемент или поддиапазон
(объект функции алгоритма)