Spec-Zone.ru › C++

std::ranges::advance

Определён в заголовочном файле <iterator>
Сигнатура вызова
template< std::input_or_output_iterator I >
constexpr void advance( I& i, std::iter_difference_t<I> n );
(1) (начиная с C++20)
template< std::input_or_output_iterator I, std::sentinel_for<I> S >
constexpr void advance( I& i, S bound );
(2) (начиная с C++20)
template< std::input_or_output_iterator I, std::sentinel_for<I> S >
constexpr std::iter_difference_t<I> advance( I& i, std::iter_difference_t<I> n, S bound );
(3) (начиная с C++20)
1) Увеличивает заданный итератор i на n раз.
2) Увеличивает заданный итератор i до i == bound.
3) Увеличивает заданный итератор i на n раз или до i == bound — в зависимости от того, что наступит раньше.

Если n отрицательно, итератор уменьшается. В этом случае I должен соответствовать требованиям std::bidirectional_iterator, а S должен иметь тот же тип, что и I, если задан bound; в противном случае поведение не определено.

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

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

Параметры

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

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

3) Разность между n и фактически пройденным расстоянием i.

Сложность

Линейная.

Однако если I дополнительно соответствует требованиям std::random_access_iterator, или S соответствует требованиям std::sized_sentinel_for<I>, или I и S соответствуют требованиям std::assignable_from<I&, S>, сложность постоянная.

Примечания

Поведение не определено, если указанная последовательность увеличений или уменьшений требует увеличить итератор, который нельзя увеличить (например, итератор за концом диапазона), или уменьшить итератор, который нельзя уменьшить (например, итератор на первом элементе или сингулярный итератор).

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

struct advance_fn
{
    template<std::input_or_output_iterator I>
    constexpr void operator()(I& i, std::iter_difference_t<I> n) const
    {
        if constexpr (std::random_access_iterator<I>)
            i += n;
        else
        {
            while (n > 0)
            {
                --n;
                ++i;
            }

            if constexpr (std::bidirectional_iterator<I>)
            {
                while (n < 0)
                {
                    ++n;
                    --i;
                }
            }
        }
    }

    template<std::input_or_output_iterator I, std::sentinel_for<I> S>
    constexpr void operator()(I& i, S bound) const
    {
        if constexpr (std::assignable_from<I&, S>)
            i = std::move(bound);
        else if constexpr (std::sized_sentinel_for<S, I>)
            (*this)(i, bound - i);
        else
            while (i != bound)
                ++i;
    }

    template<std::input_or_output_iterator I, std::sentinel_for<I> S>
    constexpr std::iter_difference_t<I>
    operator()(I& i, std::iter_difference_t<I> n, S bound) const
    {
        if constexpr (std::sized_sentinel_for<S, I>)
        {
            // std::abs is not constexpr until C++23
            auto abs = [](const std::iter_difference_t<I> x) { return x < 0 ? -x : x; };

            if (const auto dist = abs(n) - abs(bound - i); dist < 0)
            {
                (*this)(i, bound);
                return -dist;
            }

            (*this)(i, n);
            return 0;
        }
        else
        {
            while (n > 0 && i != bound)
            {
                --n;
                ++i;
            }

            if constexpr (std::bidirectional_iterator<I>)
            {
                while (n < 0 && i != bound)
                {
                    ++n;
                    --i;
                }
            }

            return n;
        }
    }
};

inline constexpr auto advance = advance_fn();

Пример

#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> v {3, 1, 4};

    auto vi = v.begin();

    std::ranges::advance(vi, 2);
    std::cout << "1) value: " << *vi << '\n' << std::boolalpha;

    std::ranges::advance(vi, v.end());
    std::cout << "2) vi == v.end(): " << (vi == v.end()) << '\n';

    std::ranges::advance(vi, -3);
    std::cout << "3) value: " << *vi << '\n';

    std::cout << "4) diff: " << std::ranges::advance(vi, 2, v.end())
              << ", value: " << *vi << '\n';

    std::cout << "5) diff: " << std::ranges::advance(vi, 4, v.end())
              << ", vi == v.end(): " << (vi == v.end()) << '\n';
}

Вывод:

1) value: 4
2) vi == v.end(): true
3) value: 3
4) diff: 0, value: 4
5) diff: 3, vi == v.end(): true

См. также

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

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

Spec-Zone.ru

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