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/w/cpp/iterator/ranges/distance

Spec-Zone.ru

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