Udostępnij za pośrednictwem


Adaptery zakresowe

Adaptery zakresów tworzą widok (jedna z klas Widok w std::views przestrzeni nazw) z zakresu. Zalecamy użycie adaptera do tworzenia widoków zamiast bezpośredniego tworzenia typów widoków. Adaptery są zamierzonym sposobem uzyskiwania dostępu do widoków. Są one łatwiejsze do użycia, a w niektórych przypadkach bardziej wydajne niż bezpośrednie tworzenie wystąpień typów widoków.

Widok to lekki obiekt, który odwołuje się do elementów z zakresu. Widok może:

  • Składa się tylko z niektórych elementów z zakresu.
  • Reprezentują transformację elementów z zakresu.
  • Być odwrotnym lub tylko pierwszymi n elementami zakresu.
  • Bądź kombinacją powyższych rzeczy.

Widok jest tani, , O(1)do kopiowania, przypisywania i niszczenia — bez względu na to, ile elementów jest zaangażowanych. Rozważmy następujący przykład:

// 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

Pierwszy adapter zakresu, filter, zapewnia widok zawierający elementy z input tych, które są podzielne przez trzy. Drugi adapter zakresu, transform, przyjmuje widok, który zawiera elementy podzielne przez trzy i zapewnia widok kwadratu tych elementów.

Gdy adapter zakresu generuje widok, nie wiąże się z kosztem przekształcania każdego elementu w zakresie w celu utworzenia tego widoku. Koszt przetwarzania elementu w widoku jest płatny tylko wtedy, gdy uzyskujesz dostęp do tego elementu.

Tworzenie widoku to przygotowanie do pracy w przyszłości. W poprzednim przykładzie utworzenie widoku nie powoduje znalezienia wszystkich elementów podzielnych przez trzy lub kwadraty tych elementów. Praca odbywa się tylko wtedy, gdy uzyskujesz dostęp do elementu w widoku.

Elementy widoku są zwykle rzeczywistymi elementami zakresu użytego do utworzenia widoku. Widok zwykle nie jest właścicielem elementów; to po prostu odnosi się do nich, z wyjątkiem owning_view. Zmiana elementu zmienia ten element w zakresie, na podstawie którego utworzono widok. W poniższym przykładzie pokazano to zachowanie:

#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
    }
}

Adaptery zakresowe są dostępne w wielu formach. Istnieją na przykład adaptery zakresu, które umożliwiają tworzenie widoku przez:

  • Filtrowanie innego zakresu na podstawie predykatu (filter).
  • Przekształcanie elementów w zakresie (transform).
  • Dzielenie zakresu (split).

Adaptery zakresowe można łączyć ze sobą (składać). W tym miejscu najbardziej widoczna jest moc i elastyczność zakresów. Komponowanie adapterów zakresu umożliwia rozwiązanie podstawowego problemu z poprzednimi algorytmami standardowej biblioteki szablonów (STL), co oznacza, że nie są łatwe do łączenia ze sobą.

Następujące adaptery zakresu są dostępne w std::views przestrzeni nazw. std::views Przestrzeń nazw jest aliasem wygody dla elementu std::ranges::views.

Adapter zakresu opis
allC++20 Utwórz widok odwołujący się do zakresu i jego elementów.
commonC++20 Utwórz widok z tym samymi typami iteratora i sentynel z zakresu, który nie jest.
countedC++20 Utwórz widok pierwszych n elementów zakresu, zaczynając od określonej lokalizacji.
dropC++20 Utwórz widok z innego widoku, pomijając określoną liczbę elementów z przodu.
drop_whileC++20 Utwórz widok zawierający elementy zakresu, które pozostają po porzuceniu elementów wiodących, które pasują do określonego warunku.
elementsC++20 Utwórz widok wybranego indeksu w każdej wartości podobnej do krotki w zakresie.
emptyC++20 Utwórz widok, który nie zawiera żadnych elementów.
filterC++20 Utwórz widok zawierający elementy zakresu zgodnego z określonym warunkiem.
iotaC++20 Utwórz widok zawierający sekwencję rosnących wartości.
istreamC++20 Utwórz widok nad elementami strumienia.
joinC++20 Utwórz widok, który łączy wszystkie elementy wielu zakresów w jeden widok.
keysC++20 Utwórz widok pierwszego indeksu w każdej wartości podobnej do krotki w kolekcji.
lazy_splitC++20 Podziel widok na podgrupy na podstawie ogranicznika.
reverseC++20 Utwórz widok elementów zakresu w odwrotnej kolejności.
singleC++20 Utwórz widok zawierający jeden element.
splitC++20 Podziel widok na podgrupy na podstawie ogranicznika.
takeC++20 Utwórz widok pierwszych n elementów z innego widoku.
take_whileC++20 Utwórz widok zawierający wiodące elementy zakresu zgodnego z określonym warunkiem.
transformC++20 Utwórz widok przekształconych elementów z innego widoku.
valuesC++20 Utwórz widok drugiego indeksu w każdej wartości podobnej do krotki w kolekcji.

W poprzedniej tabeli adapter zakresu jest zwykle opisywany jako pobieranie zakresu i tworzenie widoku. Aby być precyzyjnym, adaptery zakresu mają argument zakresu, który akceptuje jeden z następujących elementów:

  • Modele cv-unqualifiedviewtypów , a argument jest rvalue lub można go skopiować.
  • Po przekazaniu argumentu jako lvalue musi on modelować range i żyć tak długo, jak widok.
  • Po przekazaniu argumentu jako wartości rvalue, takiej jak podczas wywoływania owning_viewmetody , musi ona modelować range i movable.

Funkcje adaptera zakresu są zwykle obiektami funkcji, które wyglądają jak wywołania funkcji i wymuszają ograniczenia dotyczące typów, które mogą być przekazywane.

Można przekazać adaptery zakresu i wynik operacji potoku (|) do kodu, który oczekuje obiektów funkcji. W poniższym przykładzie widok tworzony przez split adapter zakresu jest przekazywany do transform adaptera zakresu tak, jakby przez wywołanie funkcji, ponieważ transform adapter zakresu jest obiektem funkcji.

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

Utwórz widok wszystkich elementów w zakresie.

template <ranges::viewable_range R>
constexpr ranges::view auto all(R&& rg) const noexcept;

Parametry

R
Typ bazowego zakresu.

rg
Zakres do utworzenia widoku.

Wartość zwracana

  • Jeśli rg jest już widok, kopia rgelementu .
  • Jeśli rg element jest wartością lvalue inną niż widok, ref_view element odwołuje się do rg. (Okres istnienia widoku jest powiązany z okresem rgistnienia .
  • Jeśli rg jest wartością rvalue inną niż widok, taką jak obiekt tymczasowy, lub jest wynikiem przekazania zakresu do std::move, .owning_view

Użyj std::views::all_t<decltype((rg))> polecenia , aby uzyskać typ zwróconego widoku.

Uwagi

Ten adapter zakresu to najlepszy sposób konwertowania zakresu na widok. Jednym z powodów tworzenia widoku z zakresu jest przekazanie go według wartości przy niskich kosztach, jeśli przekazanie zakresu według wartości może być kosztowne.

Uzyskanie widoku dla zakresu jest przydatną alternatywą dla przekazywania zakresu wagi ciężkiej według wartości, ponieważ widoki są niedrogie do tworzenia, kopiowania i niszczenia. Możliwym wyjątkiem jest owning_view, który jest widokiem, który jest właścicielem bazowego zakresu.

Ogólnie rzecz biorąc, najgorszy scenariusz niszczenia widoku ma O(N) złożoność dla liczby elementów w zakresie. Nawet w przypadku zniszczenia K kopii widoku z elementami N całkowita złożoność jest nadal O(N) taka, ponieważ podstawowy zakres jest niszczony tylko raz.

Przykład: 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

Utwórz widok, który ma ten sam typ iteratora rozpoczynającego i sentinel z zakresu, który może nie być.

template <ranges::viewable_range R>
constexpr ranges::view auto common(R&& rg) const noexcept;

Parametry

R
Typ bazowego zakresu.

rg
Zakres do utworzenia widoku.

Wartość zwracana

  • views::all(rg) jeśli rg jest zakresem z tym samym iteratorem i typem sentinel.
  • common_view(views::all(rg)) jeśli rg ma różne typy iteracyjne i sentinel.

Uwagi

Gdy interfejs API wymaga, aby iterator początkowy i końcowy sentinel miał ten sam typ, a używany widok nie spełnia tego wymagania (lub nie wiesz, czy tak nie jest), użyj tego adaptera zakresu, aby utworzyć common_viewobiekt . Gwarantuje to, że typ iteratora rozpoczęcia i typ sentynela końcowego są takie same.

Przykład: 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

Utwórz widok pierwszych count elementów zakresu, zaczynając od określonej lokalizacji.

template<class Iterator>
constexpr auto counted(Iterator&& it, iter_difference_t<Iterator> count);

Parametry

DifferenceType
Typ liczby.

Iterator
Typ iteratora.

count
Liczba elementów do uwzględnienia w widoku. Musi być nieujemna.

  • Jeśli count == 0zostanie zwrócona wartość , zostanie zwrócona pusta span wartość .
  • Jeśli count jest większa niż liczba elementów w zakresie, zachowanie jest niezdefiniowane.

it
Iterator do elementu w zakresie, na początek. Element wskazywany przez iterator znajduje się w utworzonym widoku.

Wartość zwracana

Wartość A span jest zwracana, jeśli it jest elementem contiguous_iterator dla tablic, wektorów i innych kontenerów, które przechowują swoje elementy w sposób ciągły. subrange W przeciwnym razie zwracana jest wartość .

Uwagi

Dołączone elementy to [it, count).

Po utworzeniu widoku liczba elementów w widoku pozostaje taka sama, nawet jeśli zakres, który został utworzony na podstawie zmian. Jeśli jednak zakres bazowy ulegnie zmianie, uzyskanie dostępu do elementów z widoku może spowodować niezdefiniowane zachowanie.

Przykład: 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

Utwórz widok, który wyklucza pierwsze n elementów zakresu.

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);

Parametry

DifferenceType
Typ opisujący liczbę elementów do pominięcia.

count
Liczba elementów do upuszczania z przodu elementu rg. Musi być nieujemna.

  • Jeśli count == 0zwracane są wszystkie elementy w rg pliku.
  • Jeśli count wartość jest większa niż liczba elementów w elemecie rg, zwracany jest pusty widok.

R
Typ zakresu.

rg
Zakres używany do tworzenia widoku.

Wartość zwracana

Widok zakresu bazowego z określoną liczbą elementów porzuconych z przodu.

Jeśli określisz więcej elementów do upuszczania niż istnieje w bazowym zakresie, zostanie zwrócona wartość .empty_view

Zwrócony widok jest zazwyczaj, ale nie zawsze specjalizacją .drop_view To znaczy:

Uwagi

Po jego utworzeniu liczba elementów w widoku pozostaje taka sama, nawet jeśli widok, który został utworzony na podstawie zmian. Jeśli jednak widok bazowy ulegnie zmianie, uzyskanie dostępu do elementów w zwróconym widoku może spowodować niezdefiniowane zachowanie.

drop jest przeciwieństwem take.

Kod pokazany wcześniej jako "2)" może być używany ze składnią potoku: collection | drop(5). Można go też używać ze składnią wywołania funkcji: drop(collection, 5) lub drop(5)(collection).

Przykład: 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

Utwórz widok zawierający elementy zakresu, które pozostają po porzuceniu elementów wiodących, które pasują do określonego warunku.

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);

Parametry

R
Typ zakresu.

predicate
Warunki określające, które elementy wiodące do porzucenia z zakresu.

rg
Podstawowy zakres do utworzenia widoku na podstawie.

Wartość zwracana

Element drop_while_view , który składa się z elementów, które pozostają, gdy elementy wiodące zgodne z predykatem są porzucane.

Uwagi

Zatrzymuje upuszczanie elementów z rg jak tylko predykat zwraca falsewartość .

drop_while jest przeciwieństwem take_while.

Kod pokazany wcześniej jako "2)" może być używany ze składnią potoku: collection | drop_while(predicate). Można go też używać ze składnią wywołania funkcji: drop_while(collection, predicate) lub drop_while(predicate)(collection).

Przykład: 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

Utwórz obiekt elements_view, który jest widokiem wybranego indeksu na każdą wartość przypominającą krotkę w zakresie. Na przykład, biorąc pod uwagę zakres std::tuple<string, int> wartości, utwórz wszystkie elements_viewstring elementy z każdej krotki.

template<ranges::viewable_range R, size_t N>
constexpr ranges::view auto elements<N>(R&& rg);

Parametry

N
Indeks elementu do wybrania z każdej wartości podobnej do krotki do uwzględnienia w widoku.

R
Typ bazowego zakresu.

rg
Zakres wartości podobnych do krotki do utworzenia widoku.

Wartość zwracana

Element elements_view składający się z wybranego indeksu do każdej wartości podobnej do krotki w kolekcji.

Przykład: 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

Utwórz obiekt empty_view, który jest widokiem, który nie zawiera żadnych elementów.

template<class T>
inline constexpr empty_view<T> empty{};

Parametry

T
Typ elementów w widoku. Widok wymaga typu elementu, mimo że nie ma żadnych elementów.

Wartość zwracana

An empty_view.

Uwagi

Element empty_view może być przydatny podczas wywoływania kodu, który wymaga widoku, ale nie musi przetwarzać żadnego z jego elementów.

Przykład: 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

Utwórz widok zawierający elementy zakresu zgodnego z określonym warunkiem.

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);

Parametry

P
Typ predykatu.

predicate
Warunki określające, które elementy należy zachować w zakresie.

R
Typ bazowego zakresu.

rg
Zakres do utworzenia widoku.

Wartość zwracana

Element filter_view zawierający elementy zakresu zgodnego z predykatem.

Uwagi

Ze względu na wydajność, gdy używasz filter i transform razem z potokiem |, wykonaj pierwszą filter czynność, aby transform zachować tylko elementy, które zamierzasz zachować.

Kod pokazany wcześniej jako "2)" może być używany ze składnią potoku: collection | filter(predicate). Można go też używać ze składnią wywołania funkcji: filter(collection, predicate) lub filter(predicate)(collection).

Przykład: 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

Utwórz widok zawierający sekwencję rosnących wartości. Sekwencja może być ograniczona lub nie.

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

Parametry

E
Typ wartości końcowej.

S
Typ wartości początkowej.

startValue
Pierwsza wartość w sekwencji.

endValue
Ta wartość jest jedną z ostatnich wartości, która będzie znajdować się w sekwencji. Na przykład std::views::iota(0, 5) generuje widok zawierający wartości 0,1,2,3,4.

Wartość zwracana

Sekwencja iota_view rosnących wartości.

Uwagi

W przypadku niezwiązanej sekwencji zachowanie jest niezdefiniowane po osiągnięciu maksymalnej wartości jej typu danych.

Przykład: 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

Utwórz widok nad elementami strumienia.

template <class Val>
views::istream<Val>(str);

Parametry

str
Obiekt strumienia. Jego typ pochodzi od specjalizacji std::basic_istream.

Val
Typ elementów do wyodrębnienia ze strumienia.

Wartość zwracana

Klasa basic_istream_view.

Ten adapter zakresu jest odpowiednikiem ranges::basic_istream_view<Val, typename U::char_type, typename U::traits_type>(str)parametru , gdzie U jest typem str.

Przykład: 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

Utwórz widok, który łączy wszystkie elementy wielu zakresów w jeden widok.

1) template <ranges::viewable_range R>
[[nodiscard]] constexpr ranges::view auto join(R&& rg) const noexcept;

2) inline constexpr /*range adaptor closure*/ join();

Parametry

R
Typ bazowego zakresu.

rg
Zakres do utworzenia widoku.

Wartość zwracana

Element join_view zawierający elementy wszystkich zakresów w bazowym zakresie.

Przykład: 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.

Uwagi

Kod pokazany wcześniej jako "2)" może być używany ze składnią potoku: collection | join. Można go też używać ze składnią wywołania funkcji: join(collection).

keys

Utwórz pierwszy keys_view indeks w każdej wartości podobnej do krotki w kolekcji. Jest to przydatne w przypadku wyodrębniania kluczy z kontenerów asocjacyjnych. Na przykład, biorąc pod uwagę zakres std::tuple<string, int>, utwórz widok, który składa się ze wszystkich string elementów z każdej krotki.

template <ranges::viewable_range R>
constexpr auto keys(R&& rg);

Parametry

R
Typ bazowego zakresu.

Wartość zwracana

Element keys_view składający się z pierwszego indeksu do każdej wartości podobnej do krotki w zakresie.

Przykład: 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

Podziel zakres na podgrupy na podstawie ogranicznika. Ogranicznik może być pojedynczym elementem lub widokiem elementów.

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);

Parametry

delimiter
Pojedyncza wartość lub sekwencja wartości określających, gdzie należy podzielić zakres.

Pattern
Typ ogranicznika.

R
Typ zakresu, który ma być podzielony.

rg
Zakres do podzielenia.

Wartość zwracana

Element lazy_split_view , który zawiera co najmniej jedną podranges i jest wynikiem podziału oryginalnego zakresu na delimiter.

Uwagi

Ogranicznik nie jest częścią wyniku. Jeśli na przykład podzielisz zakres 1,2,3 na wartość 2, uzyskasz dwa podgrupy: 1 i 3.

Powiązany adapter to split. Podstawowe różnice między [split_view](split-view-class.md) and lazy_split_view" to:

Wyświetlanie Może podzielić const zakres Iterator zakresu
split_view nie Obsługuje forward_range lub wyższe
lazy_split_view tak input_range lub nowszy

Preferuj split_view , ponieważ jest bardziej wydajny, chyba że musisz podzielić zakres, który ma wartość const.

Kod pokazany wcześniej jako "2)" może być używany ze składnią potoku: collection | lazy_split(delimiter). Można go też używać ze składnią wywołania funkcji: lazy_split(collection, delimiter) lub lazy_split(delimiter)(collection).

Przykład: 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

Utwórz widok elementów zakresu w odwrotnej kolejności.

1) template<viewable_range R>
constexpr ranges::view auto reverse(R&& rg);

2) inline constexpr /*range adaptor closure*/ reverse();

Parametry

R
Typ bazowego zakresu do odwrócenia.

rg
Zakres do odwrócenia.

Wartość zwracana

Widok przedstawiający elementy bazowego zakresu w odwrotnej kolejności. Zwrócony widok jest zazwyczaj, ale nie zawsze specjalizacją .reverse_view To znaczy:

  • Jeśli V jest specjalizacją reverse_viewklasy , wynikiem jest widok podstawowy argumentu. Podwójna odwrotność jest operacją no-op (bez operacji).
  • Jeśli V ma formularz subrange<reverse_iterator<I>, reverse_iterator<I>>, wynikiem jest subrange iteratory niezapisane. Podwójna odwrotność to no-op.
  • W przeciwnym razie wynik to reverse_view.

Uwagi

Kod pokazany wcześniej jako "2)" może być używany ze składnią potoku: collection | reverse. Można go też używać ze składnią wywołania funkcji: reverse(collection).

Przykład: 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

Utwórz obiekt single_view, który jest widokiem zawierającym jeden element.

template<class T>
constexpr ranges::view auto single(T&& t);

Parametry

T
Typ elementu w widoku.

t
Wartość elementu do przechowywania w widoku.

Wartość zwracana

Obiekt single_view zawierający telement .

Uwagi

Ten widok jest przydatny do celów testowych w celu wywoływania kodu, który musi zostać udostępniony z widokiem zawierającym co najmniej jeden element.

Przykład: 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

Podziel widok na podgrupy na podstawie ogranicznika. Ogranicznik może być pojedynczym elementem lub sekwencją elementów.

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);

Parametry

delimiter
Pojedyncza wartość lub sekwencja wartości określających, gdzie należy podzielić zakres.

Pattern
Typ ogranicznika.

R
Typ bazowego zakresu do podzielenia.

rg
Zakres do podzielenia.

Wartość zwracana

Element split_view zawierający co najmniej jedną podgrupę.

Uwagi

Ogranicznik nie jest częścią wyniku. Jeśli na przykład podzielisz zakres 1,2,3 na wartość 2, uzyskasz dwa podgrupy: 1 i 3.

Powiązany adapter to lazy_split. Podstawowe różnice między elementami split_view i lazy_split_view to:

Wyświetlanie Może podzielić const zakres Typ zakresu
split_view nie Obsługuje forward_range lub wyższe
lazy_split_view tak Obsługuje input_range lub wyższe

Preferuj split_view , ponieważ jest bardziej wydajny, chyba że musisz podzielić zakres, który ma wartość const.

Kod pokazany wcześniej jako "2)" może być używany ze składnią potoku: collection | split(delimiter). Można go też używać ze składnią wywołania funkcji: split(collection, 5) lub split(5)(collection).

Przykład: 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

Utwórz widok zawierający określoną liczbę elementów pobranych z przodu zakresu.

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); 

Parametry

R
Typ bazowego zakresu.

rg
Zakres do utworzenia widoku.

count
Liczba elementów do podjęcia z przodu elementu rg.

Wartość zwracana

Zwrócony widok jest zazwyczaj, ale nie zawsze specjalizacją .take_view Szczególnie:

Uwagi

Jeśli określisz więcej elementów do podjęcia niż istnieje w rgelemecie , zostaną wykonane wszystkie elementy.

take jest przeciwieństwem drop.

Kod pokazany wcześniej jako "2)" może być używany ze składnią potoku: collection | take(5). Można go też używać ze składnią wywołania funkcji: take(5, collection) lub take(5)(collection).

Przykład: 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

Utwórz widok zawierający wiodące elementy zakresu zgodnego z określonym warunkiem.

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);

Parametry

P
Typ predykatu.

predicate
Warunki określające, które elementy wiodące do skopiowania z zakresu.

R
Typ bazowego zakresu.

rg
Zakres do utworzenia widoku.

Wartość zwracana

Element take_while_view składający się z pierwszych count elementów spełniających określone kryteria w zakresie.

Uwagi

Zatrzymuje pobieranie elementów z rg po powrocie false predykatu lub zakres kończy się z elementów.

take_while jest przeciwieństwem drop_while.

Kod pokazany wcześniej jako "2)" może być używany ze składnią potoku: collection | take_while(pred). Można go też używać ze składnią wywołania funkcji: take_while(collection, pred) lub take_while(pred)(collection).

Przykład: 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

Utwórz widok elementów, z których każda jest przekształceniem elementu w określonym zakresie.

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);

Parametry

F
Typ obiektu funkcji do przekształcenia elementów.

R
Typ bazowego zakresu.

fun
Funkcja, która przekształca elementy.

rg
Zakres do utworzenia widoku.

Wartość zwracana

Element transform_view zawierający przekształcone elementy elementu rg.

Uwagi

Ze względu na wydajność, podczas redagowania filter i transform, wykonaj filter najpierw, tak aby transform tylko elementy, które zamierzasz zachować.

Kod pokazany wcześniej jako "2)" może być używany ze składnią potoku: collection | transform(fun). Można go też używać ze składnią wywołania funkcji: transform(collection, fun) lub transform(fun)(collection).

Przykład: 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

Utwórz obiekt values_view , który składa się z drugiego indeksu do każdej wartości podobnej do krotki w kolekcji. Jest to przydatne w przypadku wyświetlania wartości w kontenerze asocjacyjnym. Na przykład, biorąc pod uwagę zakres std::tuple<string, int> wartości, utwórz widok składający się ze wszystkich int elementów z każdej krotki.

template <range::viewable_range R>
constexpr ranges::view auto values(R&& rg);

Parametry

R
Typ bazowego zakresu.

rg
Podstawowy zakres wartości przypominających krotki.

Wartość zwracana

Utworzony values_view na podstawie drugiego indeksu do każdej wartości podobnej do krotki w zakresie.

Przykład: 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

Aliasy typu adaptera zakresu

all_t

Zawiera typ zwracanego widoku all .

template <ranges::viewable_range R>
using all_t = decltype(views::all(std::declval<R>()));

Parametry

R
Typ bazowego zakresu.

Wartość zwracana

Typ widoku, który all zwraca wartość: decltype(views::all(std::declval<R>())).

Przykład: 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;
}

Zobacz też

<ranges>
<ranges> Pojęcia
Klasy widoków