Spec-Zone.ru › C++

std::ranges::prev

Определено в заголовке <iterator>
Подпись вызова
template< std::bidirectional_iterator I >
constexpr I prev( I i );
(1) (с C++20)
template< std::bidirectional_iterator I >
constexpr I prev( I i, std::iter_difference_t<I> n );
(2) (с C++20)
template< std::bidirectional_iterator I >
constexpr I prev( I i, std::iter_difference_t<I> n, I bound );
(3) (с C++20)

Возвращает nй предшественник итератора i.

Функциональные сущности, описанные на этой странице, являются ниблеоидами, то есть:

  • Явные списки аргументов шаблона нельзя указывать при их вызове.
  • Ни один из них не виден для поиска аргументов, зависящих от контекста.
  • Если при обычном безусловном поиске имя слева от оператора вызова функции соответствует одному из них, поиск аргументов, зависящих от контекста блокируется.

На практике они могут быть реализованы как объекты-функции или с помощью специальных расширений компилятора.

Параметры

i - итератор
n - количество элементов, на которое необходимо вернуться назад от итератора i
bound - итератор, обозначающий начало диапазона, к которому относится i

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

1) Предшественник i.
2) nй предшественник итератора i.
3) nй предшественник итератора i, или первый итератор, равный bound, в зависимости от того, что будет достигнуто раньше.

Сложность

1) Постоянная.
2,3) Постоянная, если I соответствует std::random_access_iterator<I>; в противном случае линейная.

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

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

Примечания

Хотя выражение --r.end() часто компилируется для контейнеров, это не гарантируется: r.end() является выражением-ссылкой-на-нечто-кратковременное, и нет требований к итераторам, гарантирующим работу декремента с таким выражением. В частности, когда итераторы реализуются как указатели или их operator-- квалифицируется как lvalue-ссылка, --r.end() не компилируется, в то время как ranges::prev(r.end()) компилируется.

Эта проблема усугубляется диапазонами, которые не соответствуют ranges::common_range. Например, для некоторых базовых диапазонов ranges::transform_view::end не имеет того же типа возвращаемого значения, что и ranges::transform_view::begin, и поэтому --r.end() не будет компилироваться. Это не то, с чем может помочь ranges::prev, но существуют обходные пути.

Пример

#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';
}

Вывод:

1
3

См. также

ranges::next
(C++20)
инкрементировать итератор на заданное расстояние или до заданной границы
(ниблеоид)
ranges::advance
(C++20)
смещает итератор на заданное расстояние или до заданной границы
(ниблеоид)
prev
(C++11)
декрементировать итератор
(шаблон функции)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/iterator/ranges/prev

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API