Поделиться через


Адаптеры диапазона

Адаптеры диапазона создают представление (один из классов Представления в 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
allC++20 Создайте представление, которое относится к диапазону и его элементам.
commonC++20 Создайте представление с одинаковыми итераторами и типами sentinel из диапазона, который не имеет значения.
countedC++20 Создайте представление первых n элементов диапазона, начиная с указанного расположения.
dropC++20 Создайте представление из другого представления, пропуская указанное количество элементов с передней части.
drop_whileC++20 Создайте представление, содержащее элементы диапазона, которые остаются после удаления ведущих элементов, соответствующих указанному условию.
elementsC++20 Создайте представление выбранного индекса в каждом значении кортежа в диапазоне.
emptyC++20 Создайте представление, которое не содержит элементов.
filterC++20 Создайте представление, содержащее элементы диапазона, соответствующего указанному условию.
iotaC++20 Создайте представление, содержащее последовательность увеличения значений.
istreamC++20 Создайте представление элементов потока.
joinC++20 Создайте представление, которое объединяет все элементы нескольких диапазонов в одно представление.
keysC++20 Создайте представление первого индекса в каждом кортеже, подобном значению в коллекции.
lazy_splitC++20 Разделение представления на подранги на основе разделителя.
reverseC++20 Создайте представление элементов диапазона в обратном порядке.
singleC++20 Создайте представление, содержащее один элемент.
splitC++20 Разделение представления на подранги на основе разделителя.
takeC++20 Создайте представление первых n элементов из другого представления.
take_whileC++20 Создайте представление, содержащее ведущие элементы диапазона, соответствующего указанному условию.
transformC++20 Создайте представление преобразованных элементов из другого представления.
valuesC++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. Это означает следующее.

Замечания

После создания количество элементов в представлении остается неизменным, даже если оно было создано из изменений. Однако если базовое представление изменяется, доступ к элементам в возвращаемом представлении может привести к неопределенному поведению.

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
Тип элементов, извлекаемых из потока.

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

basic_istream_view.

Этот адаптер диапазона эквивалентен 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. В частности:

Замечания

Если указать больше элементов, которые необходимо принять, чем существует 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;
}

См. также

<ranges>
<ranges> Концепции
Просмотр классов