std::ranges::distance

来自cppreference.com
< cpp‎ | iterator
 
 
迭代器库
迭代器概念
迭代器原语
算法概念与工具
间接可调用概念
常用算法要求
工具
迭代器适配器
流迭代器
迭代器定制点
迭代器操作
(C++11)
(C++11)
ranges::distance
(C++20)
范围访问
(C++11)(C++14)
(C++11)(C++14)
(C++17)(C++20)
(C++14)(C++14)
(C++14)(C++14)
(C++17)
(C++17)
 
在标头 <iterator> 定义
调用签名
template< class I, std::sentinel_for<I> S >

    requires (!std::sized_sentinel_for<S, I>)

constexpr std::iter_difference_t<I> distance( I first, S last );
(1) (C++20 起)
template< class I, std::sized_sentinel_for<std::decay_t<I>> S >

constexpr std::iter_difference_t<std::decay_t<I>>

    distance( I&& first, S last );
(2) (C++20 起)
template< ranges::range R >
constexpr ranges::range_difference_t<R> distance( R&& r );
(3) (C++20 起)
1,2) 返回从 firstlast 的自增次数。
3) 以有符号整数返回 r 的大小。

此页面上描述的仿函数实体是 niebloid,即:

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

参数

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

返回值

1) 需要从 firstlast 的自增次数。
2) last - static_cast<const std::decay_t<I>&>(first)
3)R 实现 ranges::sized_range 时返回 ranges::size(r),否则返回 ranges::distance(ranges::begin(r), ranges::end(r))

复杂度

1) 线性。
2) 常数。
3)R 实现 ranges::sized_range 时,或者在 std::sized_sentinel_for<ranges::sentinel_t<R>, ranges::iterator_t<R>> 得到实现时是常数,否则是线性。

可能的实现

struct distance_fn
{
    template<class I, std::sentinel_for<I> S>
        requires (!std::sized_sentinel_for<S, I>)
    constexpr std::iter_difference_t<I> operator()(I first, S last) const
    {
        std::iter_difference_t<I> result = 0;
        while (first != last)
        {
            ++first;
            ++result;
        }
        return result;
    }
 
    template<class I, std::sized_sentinel_for<std::decay<I>> S>
    constexpr std::iter_difference_t<I> operator()(const I& first, S last) const
    {
        return last - first;
    }
 
    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 (*this)(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

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
LWG 3392 C++20 重载 (1) 按值接收迭代器,从而拒绝拥有具大小哨位的仅移动迭代器左值 添加重载 (2)
LWG 3664 C++20 LWG 问题 3392 的解决方案导致 ranges::distance 拒绝数组实参 接受数组实参

参阅

令迭代器前进给定的距离或到给定的边界
(niebloid)
返回满足指定判别标准的元素数
(niebloid)
返回两个迭代器间的距离
(函数模板)