# std::ranges::advance

< cpp‎ | iterator

定义于头文件 `<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 ，而若提供 `bound` 则 `S` 必须与 `I` 为同一类型，否则行为未定义。

此页面上描述的仿函数实体是 niebloid ，即：

- 调用它们中的任何一者时不可指定显式模板实参。
- 它们无一对实参依赖查找可见。
- 在通常无限定查找寻找函数调用运算符左侧的名称找到它们之一时，它禁止实参依赖查找。

实际上，它们能以函数对象，或以某些特殊编译器扩展实现。

### 参数

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>) {
            ranges::advance(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
            auto abs = [](const std::iter_difference_t<I> x) { return x < 0 ? -x : x; };

            const auto dist = abs(n) - abs(bound - i);
            if (dist < 0) {
                ranges::advance(i, bound);
                return -dist;
            }

            ranges::advance(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 <iomanip>
    #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 << "value: " << *vi << '\n';

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

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

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

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

输出：

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

### 参阅

ranges::next (C++20) | 自增迭代器给定的距离或到边界 (niebloid)
ranges::prev (C++20) | 自减迭代器给定的距离或到边界 (niebloid)
ranges::distance (C++20) | 返回迭代器与哨位间的距离，或范围起始与结尾间的距离 (niebloid)
advance | 令迭代器前进给定的距离 (函数模板)