std::ranges...last_if_not(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’– std::ranges...last_if_not(3) β€” C++ Standard Library πŸ’–

manual page: std::ranges...last_if_not(3) from the C++ Standard Libary section (their spelling, not mine πŸ’€), bestie.

🌸 NAME 🌸

okay so this page is serving std::ranges::find_last, std::ranges::find_last_if, and std::ranges::find_last_if_not β€” the last-element-hunting trio. The truncated-looking manual title is just the header vibe; the real names are:

  • std::ranges::find_last
  • std::ranges::find_last_if
  • std::ranges::find_last_if_not

✨ Synopsis ✨

Defined in header <algorithm>

πŸŽ€ Call signature πŸŽ€

(1) find_last β€” iterator flavor

(since C++23) (until C++26)

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 = {} );

(since 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 = {} );

(2) find_last β€” range flavor

(since C++23) (until 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 = {} );

(since C++26)

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>
    find_last( R&& r, const T& value, Proj proj = {} );

(3) find_last_if β€” iterator flavor

(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( I first, S last, Pred pred, Proj proj = {} );

(4) find_last_if β€” range flavor

(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 = {} );

(5) find_last_if_not β€” iterator flavor

(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 = {} );

(6) find_last_if_not β€” range flavor

(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 = {} );

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 vibes:

  • __cpp_lib_ranges_find_last β€” value 202207L, std (C++23), feature ranges::find_last, ranges::find_last_if, ranges::find_last_if_not
  • __cpp_lib_algorithm_default_value_type β€” value 202403, std (C++26), feature List-initialization for algorithms (1,2)

⏭️ part 2 has the Possible implementation code blocks β€” the slower forward_iterator path is about to have its main character moment, bestie πŸ’…

✨ EXAMPLE ✨

okay bestie, this is the part where we actually run the thing πŸ˜€πŸ’– here's the full code β€” copy it, compile it, and watch it do its little dance:

// 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);
}

and the output is literally this adorable little line:

{"one", 4} {"two", 5} {"three", 6}
bestie, if you see that output, you ate and left no crumbs πŸ’…πŸ”₯

πŸ‘€ SEE ALSO πŸ‘€

like, if you're obsessed with this function (same), here are its besties:

  • 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) for each
  • 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 range. (C++20) (niebloid)
  • ranges::contains, ranges::contains_subrange β€” checks if the range contains the given element or subrange. (C++23) (niebloid) for each

that's the whole vibe ✨ page source is cppreference.com, version 2024.06.10, and the page is std::ranges...last_if_not(3). now go be the main character of your own algorithm era πŸ«ΆπŸ’–

πŸ“¦ where this page comes from