# std::ranges::distance

< cpp‎ | iterator

定义于头文件 `<iterator>` |  |
调用签名 |  |
template< std::input_or_output_iterator I, std::sentinel_for<I> S > constexpr std::iter_difference_t<I> distance( I first, S last ); | (1) | (C++20 起)
template< ranges::range R> constexpr ranges::range_difference_t<R> distance(R&& r); | (2) | (C++20 起)

1) 返回从 `first` 到 `last` 的自增次数。
2) 同 (1) ，但以 `r` 为源范围，若 `R` 实现 ranges::sized_range 则使用 ranges::size(r) ，否则如同以 ranges::begin(r) 为 `first` 并以 ranges::end(r) 为 `last` 。

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

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

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

### 参数

first | - | 指向首元素的迭代器
last | - | 代表 `first` 所指向的范围结尾的哨位
r | - | 要计算距离的范围

### 返回值

需要从 `first` 到 `last` 的自增次数。若 `I` 与 `S` 为同一类型并实现 std::sized_sentinel_for<S, I> 而且 `first` 从 `last` 可达则值可为负。

### 复杂度

1) 若 `S` 实现 std::sized_sentinel_for<S, I> 则为常数，否则为线性。
2) 若 `R` 实现 ranges::sized_range 则为常数，否则同 (1) 。

### 可能的实现

    struct distance_fn {
      template<std::input_or_output_iterator I, std::sentinel_for<I> S>
      constexpr std::iter_difference_t<I> operator()(I first, S last) const
      {
        if constexpr (std::sized_sentinel_for<S, I>) {
            return last - first;
        }
        else {
            std::iter_difference_t<I> result = 0;
            while (first != last) {
                ++first;
                ++result;
            }
            return result;
        }
      }

      template<ranges::range R>
      constexpr ranges::range_difference_t<R> operator()(R&& r) const
      {
        if constexpr (ranges::sized_range<std::remove_cvref_t<R>>) {
          return static_cast<ranges::range_difference_t<R>>(ranges::size(r));
        }
        else {
          return ranges::distance(ranges::begin(r), ranges::end(r));
        }
      }
    };

    inline constexpr auto distance = distance_fn{};

### 示例

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

    int main()
    {
        std::vector<int> v{ 3, 1, 4 };
        namespace ranges = std::ranges;
        std::cout << "distance(first, last) = "
                  << ranges::distance(v.begin(), v.end()) << '\n'
                  << "distance(last, first) = "
                  << ranges::distance(v.end(), v.begin()) << '\n'
                  << "distance(v) = " << ranges::distance(v) << '\n';
    }

输出：

    distance(first, last) = 3
    distance(last, first) = -3
    distance(v) = 3

### 参阅

ranges::advance (C++20) | 令迭代器前进给定的距离或到给定的边界 (niebloid)
ranges::count ranges::count_if (C++20)(C++20) | 返回满足指定判别标准的元素数 (niebloid)
distance | 返回两个迭代器间的距离 (函数模板)