Namespaces
Variants

std::ranges:: advance

From cppreference.net
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
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)
Определено в заголовке <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 , иначе поведение не определено.

Описываемые на этой странице функциональные сущности являются algorithm function objects (неформально известными как niebloids ), то есть:

  • Явные списки аргументов шаблона не могут быть указаны при вызове любого из них.
  • Ни один из них не видим для argument-dependent lookup .
  • Когда любой из них найден с помощью normal unqualified lookup как имя слева от оператора вызова функции, argument-dependent lookup блокируется.

Содержание

Параметры

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 не является constexpr до 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) значение: " << *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) значение: " << *vi << '\n';
    std::cout << "4) разница: " << std::ranges::advance(vi, 2, v.end())
              << ", значение: " << *vi << '\n';
    std::cout << "5) разница: " << 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

Смотрите также

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