Spec-Zone.ru › C++

std::ranges::distance

Определено в заголовочном файле <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) Возвращает количество шагов от first до last.
3) Возвращает размер r в виде целого числа со знаком.

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

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

Параметры

first - итератор, указывающий на первый элемент
last - сентинел, обозначающий конец диапазона, first является итератором к
r - диапазон, расстояние до конца которого требуется вычислить

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

1) Количество инкрементов, необходимых для перехода от first к last.
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 <cassert>
#include <forward_list>
#include <iterator>
#include <vector>

int main() 
{
    std::vector<int> v{3, 1, 4};
    assert(std::ranges::distance(v.begin(), v.end()) == 3);
    assert(std::ranges::distance(v.end(), v.begin()) == -3);
    assert(std::ranges::distance(v) == 3);

    std::forward_list<int> l{2, 7, 1};
    // auto size = std::ranges::size(l); // error: not a sizable range
    auto size = std::ranges::distance(l); // OK, but aware O(N) complexity
    assert(size == 3);
}

Отчеты об ошибках

Следующие отчеты об ошибках, изменяющие поведение, были применены задним числом к ранее опубликованным стандартам C++.

DR Применяется к Опубликованное поведение Правильное поведение
LWG 3392 C++20 перегрузка (1) принимает итератор по значению, поэтому итератор lvalue, доступный только для перемещения,
с сентинелом с размером не принимался
добавлена перегрузка (2)
LWG 3664 C++20 решение вопроса LWG 3392 приводило к тому, что
ranges::distance отклонял аргументы-массивы
принимает их

См. также

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

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

Spec-Zone.ru

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