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 отклонял аргументы-массивы | принимает их |
См. также
|
(C++20) | перемещает итератор на заданное расстояние или до заданной границы (объект-функция алгоритма) |
|
(C++20)(C++20) | возвращает количество элементов, удовлетворяющих заданным критериям (объект-функция алгоритма) |
| возвращает расстояние между двумя итераторами (шаблон функции) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/iterator/ranges/distance