std::ranges::prev

From cppreference.com
< cpp‎ | iterator
 
 
Iterator library
Iterator concepts
Iterator primitives
Algorithm concepts and utilities
Indirect callable concepts
Common algorithm requirements
(C++20)
(C++20)
(C++20)
Utilities
(C++20)
Iterator adaptors
Iterator operations
(C++11)  
(C++11)
ranges::prev
(C++20)
Range access
(C++11)(C++14)
(C++14)(C++14)  
(C++11)(C++14)
(C++14)(C++14)  
(C++17)(C++20)
(C++17)
(C++17)
 
Defined in header <iterator>
Call signature
template< std::bidirectional_iterator I >
constexpr I prev( I i );
(1) (since C++20)
template< std::bidirectional_iterator I >
constexpr I prev( I i, std::iter_difference_t<I> n );
(2) (since C++20)
template< std::bidirectional_iterator I >
constexpr I prev( I i, std::iter_difference_t<I> n, I bound );
(3) (since C++20)

Return the nth predecessor of iterator i.

The function-like entities described on this page are niebloids, that is:

In practice, they may be implemented as function objects, or with special compiler extensions.

Parameters

i - an iterator
n - number of elements i should be descended
bound - iterator denoting the beginning of the range i points to

Return value

1) The predecessor of i.
2) The nth predecessor of iterator i.
3) The nth predecessor of iterator i, or the first iterator that compares equal to bound, whichever is first.

Complexity

1) Constant.
2,3) Constant if I models std::random_access_iterator<I>; otherwise linear.

Possible implementation

struct prev_fn
{
    template<std::bidirectional_iterator I>
    constexpr I operator()(I i) const
    {
        --i;
        return i;
    }
 
    template<std::bidirectional_iterator I>
    constexpr I operator()(I i, std::iter_difference_t<I> n) const
    {
        ranges::advance(i, -n);
        return i;
    }
 
    template<std::bidirectional_iterator I>
    constexpr I operator()(I i, std::iter_difference_t<I> n, I bound) const
    {
        ranges::advance(i, -n, bound);
        return i;
    }
};
 
inline constexpr auto prev = prev_fn();

Notes

Although the expression --r.end() often compiles for containers, it is not guaranteed to do so: r.end() is an rvalue expression, and there is no iterator requirement that specifies that decrement of an rvalue is guaranteed to work. In particular, when iterators are implemented as pointers or its operator-- is lvalue-ref-qualified, --r.end() does not compile, while ranges::prev(r.end()) does.

This is further exacerbated by ranges that do not model ranges::common_range. For example, for some underlying ranges, ranges::transform_view::end doesn't have the same return type as ranges::transform_view::begin, and so --r.end() won't compile. This isn't something that ranges::prev can aid with, but there are workarounds.

Example

#include <iostream>
#include <iterator>
#include <vector>
 
int main() 
{
    std::vector<int> v{3, 1, 4};
    auto pv = std::ranges::prev(v.end(), 2);
    std::cout << *pv << '\n';
 
    pv = std::ranges::prev(pv, 42, v.begin());
    std::cout << *pv << '\n';
}

Output:

1
3

See also

increment an iterator by a given distance or to a bound
(niebloid)
advances an iterator by given distance or to a given bound
(niebloid)
(C++11)
decrement an iterator
(function template)