Адаптеры диапазона
Адаптеры диапазона создают представление (один из классов Представления в std::views
пространстве имен) из диапазона. Рекомендуется использовать адаптер для создания представлений вместо создания типов представлений напрямую. Адаптеры предназначены для доступа к представлениям. Они проще использовать, а в некоторых случаях эффективнее, чем создавать экземпляры типов представлений напрямую.
Представление — это упрощенный объект, ссылающийся на элементы из диапазона. Представление может:
- Состоит только из определенных элементов из диапазона.
- Представляет преобразование элементов из диапазона.
- Будьте обратным или единственными первыми
n
элементами диапазона. - Будьте сочетанием предыдущих вещей.
Представление дешево, O(1)
для копирования, назначения и уничтожения независимо от количества элементов. Рассмотрим следующий пример:
// requires /std:c++20 or later
#include <ranges>
#include <vector>
#include <iostream>
int main()
{
std::vector<int> input = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto divisible_by_three = [](const int n) {return n % 3 == 0;};
auto square = [](const int n) {return n * n;};
auto x = input | std::views::filter(divisible_by_three)
| std::views::transform(square);
for (int i : x)
{
std::cout << i << ' ';
}
}
0 9 36 81
Первый адаптер filter
диапазона предоставляет представление, содержащее элементы из input
них, делимые на три. Другой адаптер диапазона принимает transform
представление, содержащее элементы, делимые на три, и предоставляет представление квадрата этих элементов.
Когда адаптер диапазона создает представление, это не влечет за собой затраты на преобразование каждого элемента в диапазоне для создания этого представления. Плата за обработку элемента в представлении оплачивается только при доступе к элементу.
Создание представления — подготовка к работе в будущем. В предыдущем примере создание представления не приводит к поиску всех элементов, делимых тремя или кратными этими элементами. Работа происходит только при доступе к элементу в представлении.
Элементы представления обычно являются фактическими элементами диапазона, используемого для создания представления. Представление обычно не владеет элементами; он просто ссылается на них, за исключением owning_view
. Изменение элемента в диапазоне, из которому было создано представление. В следующем примере показано следующее поведение:
#include <algorithm>
#include <iostream>
#include <ranges>
int main()
{
int input[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto even = [](const int n) { return n % 2 == 0; };
auto x = input | std::views::filter(even); // create a view of the even elements from input
for (int &i : x)
{
std::cout << i << ' '; // 0 2 4 6 8 10
}
std::cout << '\n';
std::ranges::fill(x, 42); // changes the evens from input[] to 42
for (int &i : input) // demonstrates that the even elements in the range are modified
{
std::cout << i << ' '; // // 42 1 42 3 42 5 42 7 42 9 42
}
}
Адаптеры диапазона бывают во многих формах. Например, существуют адаптеры диапазона, позволяющие создавать представление следующим образом:
- Фильтрация другого диапазона на основе предиката (
filter
). - Преобразование элементов в диапазоне (
transform
). - Разделение диапазона (
split
).
Адаптеры диапазона можно объединить (состоит). Вот где сила и гибкость диапазонов наиболее очевидны. Создание адаптеров диапазона позволяет преодолеть основную проблему с предыдущими алгоритмами стандартной библиотеки шаблонов (STL), что заключается в том, что они не просты в цепочке.
В пространстве имен доступны std::views
следующие адаптеры диапазона. Пространство std::views
имен — это удобный псевдоним.std::ranges::views
Адаптер диапазона | Description |
---|---|
all C++20 |
Создайте представление, которое относится к диапазону и его элементам. |
common C++20 |
Создайте представление с одинаковыми итераторами и типами sentinel из диапазона, который не имеет значения. |
counted C++20 |
Создайте представление первых n элементов диапазона, начиная с указанного расположения. |
drop C++20 |
Создайте представление из другого представления, пропуская указанное количество элементов с передней части. |
drop_while C++20 |
Создайте представление, содержащее элементы диапазона, которые остаются после удаления ведущих элементов, соответствующих указанному условию. |
elements C++20 |
Создайте представление выбранного индекса в каждом значении кортежа в диапазоне. |
empty C++20 |
Создайте представление, которое не содержит элементов. |
filter C++20 |
Создайте представление, содержащее элементы диапазона, соответствующего указанному условию. |
iota C++20 |
Создайте представление, содержащее последовательность увеличения значений. |
istream C++20 |
Создайте представление элементов потока. |
join C++20 |
Создайте представление, которое объединяет все элементы нескольких диапазонов в одно представление. |
keys C++20 |
Создайте представление первого индекса в каждом кортеже, подобном значению в коллекции. |
lazy_split C++20 |
Разделение представления на подранги на основе разделителя. |
reverse C++20 |
Создайте представление элементов диапазона в обратном порядке. |
single C++20 |
Создайте представление, содержащее один элемент. |
split C++20 |
Разделение представления на подранги на основе разделителя. |
take C++20 |
Создайте представление первых n элементов из другого представления. |
take_while C++20 |
Создайте представление, содержащее ведущие элементы диапазона, соответствующего указанному условию. |
transform C++20 |
Создайте представление преобразованных элементов из другого представления. |
values C++20 |
Создайте представление второго индекса в каждом кортеже, подобном значению в коллекции. |
В предыдущей таблице адаптер диапазона обычно описывается как прием диапазона и создание представления. Чтобы быть точным, адаптеры диапазона имеют аргумент диапазона, который принимает один из следующих вариантов:
- Модели
cv-unqualified
view
типов, а аргумент — rvalue или можно скопировать. - При передаче аргумента в виде lvalue он должен моделировать
range
и жить до тех пор, пока представление. - При передаче аргумента в виде rvalue, например при вызове
owning_view
, он должен моделироватьrange
иmovable
.
Функции адаптера диапазона обычно представляют собой объекты-функции, которые выглядят как вызовы функций и применяют ограничения для передаваемых типов.
Можно передать адаптеры диапазона и результат операций канала (|
) в код, который ожидает объекты функций. В следующем примере представление, которое split
создает адаптер диапазона, передается transform
адаптеру диапазона, как при вызове функции, так как transform
адаптер диапазона является объектом функции.
std::map<int, string> x = {{0, "Hello, world"}, {42, "Goodbye, world"}};
auto y = x | views::values | views::transform(views::split(' '));
// y is a range whose elements are ranges of whitespace-delimited strings from each value in x:
// {{"Hello", "world"}, {"Goodbye", "world"}}
all
Создайте представление всех элементов в диапазоне.
template <ranges::viewable_range R>
constexpr ranges::view auto all(R&& rg) const noexcept;
Параметры
R
Тип базового диапазона.
rg
Диапазон для создания представления из.
Возвращаемое значение
- Если
rg
представление уже является представлением, копияrg
. - Если
rg
значение lvalue не является представлением, тоref_view
это относится кrg
. (Время существования представления связано с временем существованияrg
.) - Если
rg
значение rvalue не является представлением, например временным объектом, или результатом передачи диапазонаstd::move
в .owning_view
Используется std::views::all_t<decltype((rg))>
для получения типа возвращаемого представления.
Замечания
Этот адаптер диапазона является лучшим способом преобразования диапазона в представление. Одна из причин создания представления из диапазона заключается в том, чтобы передать его по низкой стоимости, если передача диапазона по значению может быть дорогой.
Получение представления для диапазона является полезной альтернативой передаче тяжелого диапазона по значению, так как представления являются недорогими для создания, копирования и уничтожения. Возможное исключение — owning_view
это представление, которое владеет базовым диапазоном.
Как правило, худший сценарий уничтожения представления имеет O(N)
сложность для количества элементов в диапазоне. Даже если вы уничтожаете K
копии представления с N
элементами, общая сложность по-прежнему обусловлена O(N)
тем, что базовый диапазон уничтожается только один раз.
Пример: all
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v = {1,2,3,4,5,6,7,8,9,10};
auto myRefView = std::views::all(v); // create a ref_view of the vector
std::cout << myRefView.size() << '\n'; // 10
auto myOwningView = std::views::all(std::move(v)); // create an owning_view from a moved vector
std::cout << myRefView.size() << '\n'; // outputs 0 because myOwningView now owns the elements
std::cout << v.size() << '\n'; // outputs 0 because myOwningView now owns the elements
std::cout << myOwningView.size(); // 10
}
10
0
0
10
common
Создайте представление, которое имеет тот же итератор и тип sentinel из диапазона, который может не быть.
template <ranges::viewable_range R>
constexpr ranges::view auto common(R&& rg) const noexcept;
Параметры
R
Тип базового диапазона.
rg
Диапазон для создания представления из.
Возвращаемое значение
views::all(rg)
Значениеrg это диапазон с одинаковым итератором и типом sentinel. common_view(views::all(rg))
Значение , еслиrg
имеет разные итераторы и типы sentinel.
Замечания
Если API требует, чтобы начальный итератор и конечный sentinel имели тот же тип, и представление, которое вы используете, не соответствует этому требованию (или вы не знаете, если это делает), используйте этот адаптер диапазона для создания common_view
. Это гарантирует, что тип итератора начала и тип конечного sentinel совпадают.
Пример: common
// requires /std:c++20 or higher
#include <ranges>
#include <iostream>
#include <numeric>
#include <list>
int main()
{
std::list<int> lst{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto firstFive = std::views::take(lst, 5);
// firstFive.begin(), firstFive.end() have different types: counted_iterator versus default_sentinel
// auto r = std::accumulate(firstFive.begin(), firstFive.end(), 0); // Error: accumulate() requires firstFive.begin() and firstFive.end() types to be the same.
auto common = std::views::common(firstFive); // create a common_view that has the same begin/end iterator types
std::cout << std::accumulate(common.begin(), common.end(), 0); // Now you can call the API because the iterator types are the same. Outputs 15 (1+2+3+4+5)
}
15
counted
Создайте представление первых count
элементов диапазона, начиная с указанного расположения.
template<class Iterator>
constexpr auto counted(Iterator&& it, iter_difference_t<Iterator> count);
Параметры
DifferenceType
Тип счетчика.
Iterator
Тип итератора.
count
Количество элементов, включаемых в представление. Должен быть не отрицательным.
- Если
count == 0
возвращается пустоеspan
значение. - Если
count
число элементов в диапазоне больше, поведение не определено.
it
Итератор элемента в диапазоне для начала. Элемент, на который указывает итератор, входит в созданное представление.
Возвращаемое значение
Возвращается, span
если it
это contiguous_iterator
массивы, векторы и другие контейнеры, которые хранят их элементы непрерывно. В противном случае возвращается объект subrange
.
Замечания
Включенные элементы.[it, count)
После создания представления количество элементов в представлении остается неизменным, даже если диапазон, созданный из изменений. Однако если базовый диапазон изменяется, доступ к элементам из представления может привести к неопределенному поведению.
Пример: counted
// requires /std:c++20 or later
#include <algorithm>
#include <ranges>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto pos5 = std::ranges::find(v, 5);
auto countedView = std::views::counted(pos5, 5);
for (auto e : countedView) // outputs 5 6 7 8 9
{
std::cout << e << ' ';
}
std::cout << '\n';
// You can pass the range directly if it supports input_or_output_iterator, in which case
// the count starts from the first element
const char chars[] = { 'H','i',' ','t','h','e','r','e' };
for (char c : std::views::counted(chars, 2))
{
std::cout << c; // outputs Hi
}
}
5 6 7 8 9
Hi
drop
Создайте представление, которое исключает первые n-элементы диапазона.
1) template<ranges::viewable_range R>
constexpr ranges::view auto drop(R&& rg, ranges::range_difference_t<R> count);
2) template<class DifferenceType>
constexpr /* range closure object */ drop(DifferenceType&& count);
Параметры
DifferenceType
Тип, описывающий количество пропущенных элементов.
count
Количество элементов, которые нужно удалить с передней rg
части. Должен быть не отрицательным.
- Если
count == 0
возвращаются все элементыrg
. - Если
count
больше количества элементов вrg
, возвращается пустое представление.
R
Тип диапазона.
rg
Диапазон, используемый для создания представления.
Возвращаемое значение
Представление базового диапазона с указанным числом элементов, отброшенных с передней части.
Если указать больше элементов, которые нужно удалить, чем существует в базовом диапазоне, empty_view
возвращается.
Возвращаемое представление обычно, но не всегда, специализация drop_view
. Это означает следующее.
- Если
V
это специализацияempty_view
илиbasic_string_view
span
специализация , или это специализация ,iota_view
илиsubrange
то иrandom_access_range
sized_range
другое, результатом является специализацияV
. - В противном случае результатом является
drop_view
.
Замечания
После создания количество элементов в представлении остается неизменным, даже если оно было создано из изменений. Однако если базовое представление изменяется, доступ к элементам в возвращаемом представлении может привести к неопределенному поведению.
drop
противоположность take
.
Код, показанный ранее как "2)", можно использовать с синтаксисом канала: collection | drop(5)
Или его можно использовать с синтаксисом вызова функции: drop(collection, 5)
или drop(5)(collection)
.
Пример: drop
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{1, 2, 3, 4, 5};
auto newView = std::views::drop(v, 3);
for (auto e : newView) // 4 5
{
std::cout << e << ' ';
}
std::cout << '\n';
auto numbers = std::views::iota(0) | std::views::take(10); // build a view of 10 integers
auto latterHalf = numbers | std::views::drop(5);
for (auto i : latterHalf)
{
std::cout << i << ' '; // 5 6 7 8 9
}
}
4 5
5 6 7 8 9
drop_while
Создайте представление, содержащее элементы диапазона, которые остаются после удаления ведущих элементов, соответствующих указанному условию.
1) template<ranges::viewable_range R, class P>
constexpr ranges::view auto drop_while(R&& rg, P&& predicate);
2) template<class P>
constexpr /*range adaptor closure*/ drop_while(P&& predicate);
Параметры
R
Тип диапазона.
predicate
Условия, определяющие, какие ведущие элементы будут удаляться из диапазона.
rg
Базовый диапазон для создания представления из.
Возвращаемое значение
Объект, drop_while_view
состоящий из элементов, которые остаются при удалении ведущих элементов, соответствующих предикату.
Замечания
Останавливает удаление элементов сразу rg
после возврата предиката false
.
drop_while
противоположность take_while
.
Код, показанный ранее как "2)", можно использовать с синтаксисом канала: collection | drop_while(predicate)
Или его можно использовать с синтаксисом вызова функции: drop_while(collection, predicate)
или drop_while(predicate)(collection)
.
Пример: drop_while
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>
void print(auto&& v)
{
for (auto&& x : v)
{
std::cout << x << ' ';
}
std::cout << '\n';
}
int main()
{
std::vector<int> v{ 0, 1, 2, 3, -4, 5, 6 };
auto myView = std::views::drop_while(
v,
[](int i) {return i >= 0; });
print(myView); // -4 5 6
auto myView2 = v | std::views::drop_while(
[](int i) {return i < 5; });
print(myView2); // 5 6
}
-4 5 6
5 6
elements
elements_view
Создайте представление выбранного индекса в каждом кортеже, как значение в диапазоне. Например, учитывая диапазон значений std::tuple<string, int>
, создайте elements_view
все string
элементы из каждого кортежа.
template<ranges::viewable_range R, size_t N>
constexpr ranges::view auto elements<N>(R&& rg);
Параметры
N
Индекс элемента, который нужно выбрать из каждого кортежа, чтобы включить в представление.
R
Тип базового диапазона.
rg
Диапазон значений, таких как кортеж, для создания представления из.
Возвращаемое значение
Объект elements_view
, состоящий из выбранного индекса в каждом кортеже, как значение в коллекции.
Пример: elements
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <map>
#include <string>
int main()
{
std::map<std::string, int> cpp_standards
{
{"C++98", 1998},
{"C++03", 2003},
{"C++11", 2011},
{"C++14", 2014},
{"C++17", 2017},
{"C++20", 2020}
};
// Create an elements_view of all the string elements from each tuple
for (int const year : std::views::elements<1>(cpp_standards))
{
std::cout << year << ' '; // 2003 2011 2014 2017 1998 2020
}
std::cout << '\n';
// Another way, using |: create an elements_view of all the int elements from each tuple
for (auto&& name : cpp_standards | std::views::elements<0>)
{
std::cout << name << ' '; // C++03 C++11 C++14 C++17 C++98 c++20
}
}
2003 2011 2014 2017 1998 2020
C++03 C++11 C++14 C++17 C++98 c++20
empty
empty_view
Создайте представление, которое не содержит элементов.
template<class T>
inline constexpr empty_view<T> empty{};
Параметры
T
Тип элементов в представлении. В представлении требуется тип элемента, несмотря на отсутствие элементов.
Возвращаемое значение
Объект empty_view
.
Замечания
Это empty_view
может быть полезно при вызове кода, требующего представления, но не требует обработки любого из его элементов.
Пример: empty
// requires /std:c++20 or higher
#include <ranges>
#include <iostream>
int main()
{
auto anEmptyView = std::views::empty<int>;
bool isNotEmpty = (bool)anEmptyView;
std::cout << boolalpha << isNotEmpty << "\n"; // false
}
false
filter
Создайте представление, содержащее элементы диапазона, соответствующего указанному условию.
1) template<ranges::viewable_range R, class P>
requires {filter_view(forward<R>(rg), forward<P>(predicate));}
constexpr ranges::view auto filter(R&& rg, P&& predicate);
2) template<class P>
constexpr /*range adaptor closure*/ filter(P&& predicate);
Параметры
P
Тип предиката.
predicate
Условия, определяющие, какие элементы следует хранить в диапазоне.
R
Тип базового диапазона.
rg
Диапазон для создания представления из.
Возвращаемое значение
Объект, filter_view
содержащий элементы диапазона, соответствующего предикату.
Замечания
Для эффективности, когда вы используете filter
и transform
вместе с трубой |
, сделайте filter
первое, чтобы вы transform
только элементы, которые вы намерены сохранить.
Код, показанный ранее как "2)", можно использовать с синтаксисом канала: collection | filter(predicate)
Или его можно использовать с синтаксисом вызова функции: filter(collection, predicate)
или filter(predicate)(collection)
.
Пример: filter
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>
void print(auto&& v)
{
for (auto&& x : v)
{
std::cout << x << ' ';
}
std::cout << '\n';
}
int main()
{
std::vector<int> v{0, 1, 2, 3, -4, 5, 6};
auto myView = std::views::filter(v, [](int i) {return i < 5; });
print(myView); // 0 1 2 3 -4
auto myView2 = v | std::views::filter([](int i) {return i < 5; }); // pipe syntax
print(myView2); // 0 1 2 3 -4
}
0 1 2 3 -4
0 1 2 3 -4
iota
Создайте представление, содержащее последовательность увеличения значений. Последовательность может быть привязана или нет.
template<class V>
constexpr ranges::view auto iota(V&& startValue); // create an unbounded sequence of incrementing values
template<class V, class E>
constexpr ranges::view auto iota(V&& startValue, E&& endValue); // create a bounded sequence of incrementing values
Параметры
E
Тип конечного значения.
S
Тип начального значения.
startValue
Первое значение последовательности.
endValue
Это значение является одним из последних значений, которое будет находиться в последовательности. Например, std::views::iota(0, 5)
создает представление со значениями 0,1,2,3,4
.
Возвращаемое значение
Последовательность iota_view
увеличения значений.
Замечания
Для несвязанной последовательности поведение не определено после достижения максимального значения его типа данных.
Пример: iota
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
void print(auto&& v)
{
for (auto&& x : v)
{
std::cout << x << ' ';
}
std::cout << '\n';
}
int main()
{
// create an iota view with its range adaptor (preferred)
print(std::views::iota(0, 5)); // outputs 0 1 2 3 4
// create an iota_view class directly
std::ranges::iota_view letters{'a', 'f'};
print(letters); // a b c d e
}
0 1 2 3 4
a b c d e
istream
Создайте представление элементов потока.
template <class Val>
views::istream<Val>(str);
Параметры
str
Объект потока. Его тип является производным от специализации std::basic_istream
.
Val
Тип элементов, извлекаемых из потока.
Возвращаемое значение
Этот адаптер диапазона эквивалентен ranges::basic_istream_view<Val, typename U::char_type, typename U::traits_type>(str)
типу U
str
.
Пример: istream
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <sstream>
#include <vector>
int main()
{
std::istringstream doubles{"1.1 2.2 3.3 4.4 5.5"};
for (const auto& elem : std::views::istream<double>(doubles))
{
std::cout << elem << ' '; // 1.1 2.2 3.3 4.4 5.5
}
}
1.1 2.2 3.3 4.4 5.5
join
Создайте представление, которое объединяет все элементы нескольких диапазонов в одно представление.
1) template <ranges::viewable_range R>
[[nodiscard]] constexpr ranges::view auto join(R&& rg) const noexcept;
2) inline constexpr /*range adaptor closure*/ join();
Параметры
R
Тип базового диапазона.
rg
Диапазон для создания представления из.
Возвращаемое значение
Объект, join_view
содержащий элементы всех диапазонов в базовом диапазоне.
Пример: join
#include <iostream>
#include <vector>
#include <ranges>
#include <string>
int main()
{
// a range of two ranges
std::vector<std::string> rangeOfRanges[2]{{"C++20", "contains:"}, {"ranges", "modules", "concepts & more."}};
for (const auto& elem : std::views::join(rangeOfRanges))
{
std::cout << elem << ' ';
}
}
C++20 contains: ranges modules concepts & more.
Замечания
Код, показанный ранее как "2)", можно использовать с синтаксисом канала: collection | join
Или его можно использовать с синтаксисом вызова функции: join(collection)
keys
keys_view
Создайте первый индекс в каждом кортеже, как значение в коллекции. Это полезно для извлечения ключей из ассоциативных контейнеров. Например, учитывая диапазон std::tuple<string, int>
, создайте представление, состоящее из всех string
элементов из каждого кортежа.
template <ranges::viewable_range R>
constexpr auto keys(R&& rg);
Параметры
R
Тип базового диапазона.
Возвращаемое значение
Значение keys_view
, состоящее из первого индекса в каждом кортеже, как значение в диапазоне.
Пример: keys
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <map>
#include <string>
#include <vector>
int main()
{
// ========== extract keys from a map
std::map<std::string, int> cpp_standards
{
{"C++98", 1998},
{"C++03", 2003},
{"C++11", 2011},
{"C++14", 2014},
{"C++17", 2017},
{"C++20", 2020}
};
// Extract all of the keys from the map
for (std::string standards : std::views::keys(cpp_standards))
{
std::cout << standards << ' '; // C++03 C++11 C++14 C++17 C++98 C++20
}
std::cout << '\n';
// ========== Extract keys from a pair
std::vector<std::pair<std::string, int>> windows
{
{"Windows 1.0", 1985},
{"Windows 2.0", 1987},
{"Windows 3.0", 1990},
{"Windows 3.1", 1992},
{"Windows NT 3.1", 1993},
{"Windows 95", 1995},
{"Windows NT 4.0", 1996},
{"Windows 95", 1995},
{"Windows 98", 1998},
{"Windows 1.0", 1985},
{"Windows 2000", 2000}
};
// Another way to call the range adaptor is by using '|'
for (std::string version : windows | std::views::keys)
{
std::cout << version << ' '; // Windows 1.0 Windows 2.0 Windows 3.0 ...
}
}
C++03 C++11 C++14 C++17 C++98 C++20
Windows 1.0 Windows 2.0 Windows 3.0 Windows 3.1 Windows NT 3.1 Windows 95 Windows NT 4.0 Windows 95 Windows 98 Windows 1.0 Windows 2000
lazy_split
Разделение диапазона на подранги на основе разделителя. Разделитель может быть одним элементом или представлением элементов.
1) template<viewable_range R, class Pattern>
constexpr view auto lazy_split(R&& rg, Pattern&& delimiter);
2) template<class Pattern>
constexpr /*range adaptor closure*/ lazy_split(Pattern&& delimiter);
Параметры
delimiter
Одно значение или последовательность значений, указывающая место разделения диапазона.
Pattern
Тип разделителя.
R
Тип диапазона для разделения.
rg
Диапазон для разделения.
Возвращаемое значение
Объект, lazy_split_view
содержащий один или несколько подрангов, и является результатом разделения исходного диапазона на delimiter
.
Замечания
Разделитель не является частью результата. Например, если разделить диапазон 1,2,3
по значению 2
, вы получите два подранга: 1
и 3
.
Связанный адаптер .split
Основными различиями между [split_view](split-view-class.md) and
lazy_split_view' являются:
Представления | Может разделить const диапазон |
Итератор диапазона |
---|---|---|
split_view |
no | Поддерживает forward_range или выше |
lazy_split_view |
yes | input_range или выше |
Предпочитайте split_view
, так как это более эффективно, если вы не должны разделить диапазон, который является const
.
Код, показанный ранее как "2)", можно использовать с синтаксисом канала: collection | lazy_split(delimiter)
Или его можно использовать с синтаксисом вызова функции: lazy_split(collection, delimiter)
или lazy_split(delimiter)(collection)
.
Пример: lazy_split
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> rg{1, 2, 3, 1, 2, 3, 4, 5, 6};
// split on a single element
for (const auto& sub : rg | std::views::split(3))
{
// outputs:
// 1 2
// 1 2
// 4 5 6
for (const auto& elem : sub)
{
std::cout << elem << ' ';
}
std::cout << '\n';
}
// split on a sequence of elements
int delimiters[] = {2, 3};
for (const auto& subrange : std::views::split(rg, delimiters))
{
// outputs 1 1 4 5 6
for (auto& i : subrange)
{
std::cout << i << " ";
}
}
}
1 2
1 2
4 5 6
1 1 4 5 6
reverse
Создайте представление элементов диапазона в обратном порядке.
1) template<viewable_range R>
constexpr ranges::view auto reverse(R&& rg);
2) inline constexpr /*range adaptor closure*/ reverse();
Параметры
R
Тип базового диапазона для обратного.
rg
Диапазон для обратного.
Возвращаемое значение
Представление, представляющее элементы базового диапазона в обратном порядке. Возвращаемое представление обычно, но не всегда, специализация reverse_view
. Это означает следующее.
- Если
V
это специализацияreverse_view
, результатом является базовое представление аргумента. Двойной обратный — это no-op (без операции). - Если
V
форма имеетсяsubrange<reverse_iterator<I>, reverse_iterator<I>>
, результатом являетсяsubrange
распакованные итераторы. Двойной обратный — это no-op. - В противном случае результатом является
reverse_view
.
Замечания
Код, показанный ранее как "2)", можно использовать с синтаксисом канала: collection | reverse
Или его можно использовать с синтаксисом вызова функции: reverse(collection)
Пример: reverse
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{ 0, 1, 2, 3, -4, 5, 6 };
auto rv = v | std::views::reverse; // using the pipe syntax
for (auto &&e : rv) // outputs 6 5 -4 3 2 1 0
{
std::cout << e << ' ';
}
std::cout << '\n';
// using the range adaptor without using the pipe syntax
auto rv2 = std::views::reverse(v);
for (auto &&e : rv2) // outputs 6 5 -4 3 2 1 0
{
std::cout << e << ' ';
}
}
6 5 -4 3 2 1 0
6 5 -4 3 2 1 0
single
single_view
Создайте представление, содержащее один элемент.
template<class T>
constexpr ranges::view auto single(T&& t);
Параметры
T
Тип элемента в представлении.
t
Значение элемента для хранения в представлении.
Возвращаемое значение
Объект, single_view
содержащий t
.
Замечания
Это представление полезно для тестовых целей для вызова кода, который должен быть предоставлен с представлением, которое содержит по крайней мере один элемент в нем.
Пример: single
// requires /std:c++20 or higher
#include <ranges>
#include <string>
#include <tuple>
#include <iostream>
int main()
{
auto sv = std::views::single(7);
std::cout << sv.front() << " " << *sv.data() << "\n"; // 7 7
auto sv2 = std::views::single(<std::tuple<double, std::string>{6502, "8-bit"});
std::cout << std::get<0>(sv2[0]) << " " << std::get<1>(sv2[0]) << "\n"; // 6502 8-bit
}
7 7
6502 8-bit
split
Разделение представления на подранги на основе разделителя. Разделитель может быть одним элементом или последовательностью элементов.
1) template<viewable_range R, class Pattern>
constexpr view auto split(R&& rg, Pattern&& delimiter);
2) template<class Pattern>
constexpr /*range adaptor closure*/ split(Pattern&& delimiter);
Параметры
delimiter
Одно значение или последовательность значений, указывающая место разделения диапазона.
Pattern
Тип разделителя.
R
Тип базового диапазона для разделения.
rg
Диапазон для разделения.
Возвращаемое значение
Объект, split_view
содержащий один или несколько подрангов.
Замечания
Разделитель не является частью результата. Например, если разделить диапазон 1,2,3
по значению 2
, вы получите два подранга: 1
и 3
.
Связанный адаптер .lazy_split
Основные различия между split_view
ними lazy_split_view
:
Представления | Может разделить const диапазон |
Тип диапазона |
---|---|---|
split_view |
no | Поддерживает forward_range или выше |
lazy_split_view |
yes | Поддерживает input_range или выше |
Предпочитайте split_view
, так как это более эффективно, если вы не должны разделить диапазон, который является const
.
Код, показанный ранее как "2)", можно использовать с синтаксисом канала: collection | split(delimiter)
Или его можно использовать с синтаксисом вызова функции: split(collection, 5)
или split(5)(collection)
.
Пример: split
// requires /std:c++20 or later
#include <ranges>
#include <vector>
#include <iostream>
int main()
{
std::vector<int> rg{ 1, 2, 3, 1, 2, 3, 4, 5, 6 };
// split on a single element, 3
for (const auto& sub : rg | std::views::split(3))
{
// This prints out:
// 1,2
// 4,5,6
for (const auto& elem : sub)
{
std::cout << elem << ' ';
}
std::cout << '\n';
}
// split on a sequence of elements, 2,3
int delimiters[] = {2, 3};
for (const auto& subrange : std::views::split(rg, delimiters))
{
// outputs 1 1 4 5 6
for (auto& i : subrange)
{
std::cout << i << " ";
}
}
}
1 2
1 2
4 5 6
1 1 4 5 6
take
Создайте представление, содержащее указанное количество элементов, взятых из передней части диапазона.
1) template<ranges::viewable_range R>
constexpr ranges::view auto take(R&& rg, ranges::range_difference_type<R> count);
2) template<class DifferenceType>
constexpr /*range adaptor closure*/ take(DifferenceType&& count);
Параметры
R
Тип базового диапазона.
rg
Диапазон для создания представления из.
count
Количество элементов, которые нужно взять с передней rg
части.
Возвращаемое значение
Возвращаемое представление обычно, но не всегда, специализация take_view
. В частности:
- Если
V
это специализацияempty_view
илиbasic_string_view
span
специализация , или это специализация ,iota_view
илиsubrange
то иrandom_access_range
sized_range
другое, результатом является специализацияV
. - В противном случае результатом является
take_view
.
Замечания
Если указать больше элементов, которые необходимо принять, чем существует rg
, все элементы будут приняты.
take
противоположность drop
.
Код, показанный ранее как "2)", можно использовать с синтаксисом канала: collection | take(5)
Или его можно использовать с синтаксисом вызова функции: take(5, collection)
или take(5)(collection)
.
Пример: take
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::string s{ "abcdefg" };
auto myView = std::views::take(s, 3);
for (auto c : myView)
{
std::cout << c << ' '; // a b c
}
std::cout << std::endl;
for (auto c : s | std::views::take(3)) // pipe syntax
{
std::cout << c << ' '; // a b c
}
}
a b c
a b c
take_while
Создайте представление, содержащее ведущие элементы диапазона, соответствующего указанному условию.
1) template<ranges::viewable_range R, class P>
constexpr ranges::view auto take_while(R&& rg, P&& predicate);
2) template<class P>
constexpr /*range adaptor closure*/ take_while(P&& predicate);
Параметры
P
Тип предиката.
predicate
Условия, определяющие, какие ведущие элементы копируются из диапазона.
R
Тип базового диапазона.
rg
Диапазон для создания представления из.
Возвращаемое значение
A take_while_view
, состоящий из первых count
элементов, которые соответствуют указанным критериям в диапазоне.
Замечания
Останавливает прием элементов после rg
возврата false
предиката или диапазон выходит из элементов.
take_while
противоположность drop_while
.
Код, показанный ранее как "2)", можно использовать с синтаксисом канала: collection | take_while(pred)
Или его можно использовать с синтаксисом вызова функции: take_while(collection, pred)
или take_while(pred)(collection)
.
Пример: take_while
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>
void print(auto&& v)
{
for (auto&& x : v)
{
std::cout << x << ' ';
}
std::cout << '\n';
}
int main()
{
std::vector<int> v{ 0, 1, 2, 3, -4, 5, 6 };
auto myView = std::views::take_while(
v, [](int i) {return i >= 0; });
print(myView); // 0 1 2 3
print(v | std::views::take_while( // 0 1 2 3 -4
[](int i) {return i < 5; })); // pipe syntax
}
0 1 2 3
0 1 2 3 -4
transform
Создайте представление элементов, каждое из которых является преобразованием элемента в указанном диапазоне.
1) template<viewable_range R, class F>
constexpr ranges::view auto transform(R&& rg, F&& fun);
2) template<class F>
constexpr /*range adaptor closure*/ transform(F&& fun);
Параметры
F
Тип объекта функции для преобразования элементов.
R
Тип базового диапазона.
fun
Функция, которая преобразует элементы.
rg
Диапазон для создания представления из.
Возвращаемое значение
Объект, transform_view
содержащий преобразованные элементы rg
.
Замечания
Для эффективности, когда вы создаете filter
и transform
делаете первое filter
, чтобы вы transform
только элементы, которые вы намерены сохранить.
Код, показанный ранее как "2)", можно использовать с синтаксисом канала: collection | transform(fun)
Или его можно использовать с синтаксисом вызова функции: transform(collection, fun)
или transform(fun)(collection)
.
Пример: transform
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>
void print(auto&& v)
{
for (auto&& x : v)
{
std::cout << x << ' ';
}
std::cout << '\n';
}
int main()
{
std::vector<int> v{0, 1, 2, 3, -4, 5, 6};
auto myView = std::views::transform(v, [](int i) {return i * 2; });
print(myView); // 0 2 4 6 -8 10 12
print(v | std::views::transform( // 0 2 4 6 -8 10 12
[](int i) {return i * 2; })); // pipe syntax
}
0 2 4 6 -8 10 12
0 2 4 6 -8 10 12
values
values_view
Создайте элемент, состоящий из второго индекса в каждом кортеже, как значение в коллекции. Это полезно для представления значений в ассоциативном контейнере. Например, учитывая диапазон значений std::tuple<string, int>
, создайте представление, состоящее из всех int
элементов из каждого кортежа.
template <range::viewable_range R>
constexpr ranges::view auto values(R&& rg);
Параметры
R
Тип базового диапазона.
rg
Базовый диапазон значений, таких как кортеж.
Возвращаемое значение
Встроенный values_view
из второго индекса в каждое значение кортежа в диапазоне.
Пример: values
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <map>
#include <string>
#include <vector>
int main()
{
// ========== working with a map
std::map<std::string, int> cpp_standards
{
{"C++98", 1998},
{"C++03", 2003},
{"C++11", 2011},
{"C++14", 2014},
{"C++17", 2017},
{"C++20", 2020}
};
// Extract all of the years from the map
for (int years : std::views::values(cpp_standards))
{
std::cout << years << ' '; // 2003 2011 2014 2017 1998 2020
}
std::cout << '\n';
// ========== working with pairs
std::vector<std::pair<std::string, int>> windows
{
{"Windows 1.0", 1985},
{"Windows 2.0", 1987},
{"Windows 3.0", 1990},
{"Windows 3.1", 1992},
{"Windows NT 3.1", 1993},
{"Windows 95", 1995},
{"Windows NT 4.0", 1996},
{"Windows 95", 1995},
{"Windows 98", 1998},
{"Windows 1.0", 1985},
{"Windows 2000", 2000}
};
// Another way to call the range adaptor by using '|'
// Create a values_view that contains the year from each pair
for (int years : windows | std::views::values)
{
std::cout << years << ' '; // 1985 1987 1990 1992 ...
}
}
2003 2011 2014 2017 1998 2020
1985 1987 1990 1992 1993 1995 1996 1995 1998 1985 2000
Псевдонимы типа адаптера диапазона
all_t
Предоставляет тип возвращаемого all
представления.
template <ranges::viewable_range R>
using all_t = decltype(views::all(std::declval<R>()));
Параметры
R
Тип базового диапазона.
Возвращаемое значение
Тип представления, возвращаемогоall
: decltype(views::all(std::declval<R>()))
Пример: all_t
#include <ranges>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v = {1,2,3,4,5,6,7,8,9,10};
auto myView = std::views::all(v);
std::views::all_t<decltype((v))> &viewType = myView;
}