Delen via


Bereikadapters

Bereikadapters maken een weergave (een van de weergaveklassen in de std::views naamruimte) uit een bereik. U wordt aangeraden een adapter te gebruiken om weergaven te maken in plaats van de weergavetypen rechtstreeks te maken. De adapters zijn de beoogde manier om toegang te krijgen tot weergaven. Ze zijn eenvoudiger te gebruiken en in sommige gevallen efficiënter dan het rechtstreeks maken van exemplaren van de weergavetypen.

Een weergave is een lichtgewicht object dat verwijst naar elementen uit een bereik. Een weergave kan:

  • Bestaan alleen uit bepaalde elementen uit een bereik.
  • Vertegenwoordig een transformatie van elementen uit een bereik.
  • Wees het omgekeerde van of alleen de eerste n elementen van een bereik.
  • Wees een combinatie van de voorgaande dingen.

Een weergave is goedkoop, O(1)om te kopiëren, toe te wijzen en te vernietigen, ongeacht het aantal elementen. Bekijk het volgende voorbeeld:

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

De eerste bereikadapter, filterbiedt een weergave die de elementen bevat input die deelbaar zijn door drie. De andere bereikadapter, transformneemt de weergave met de elementen deelbaar door drie en geeft een beeld van het vierkant van die elementen.

Wanneer een bereikadapter een weergave produceert, worden er geen kosten in rekening gebracht voor het transformeren van elk element in het bereik om die weergave te produceren. De kosten voor het verwerken van een element in de weergave worden alleen betaald wanneer u dat element opent.

Het maken van een weergave is de voorbereiding op het uitvoeren van werk in de toekomst. In het vorige voorbeeld resulteert het maken van de weergave niet in het vinden van alle elementen die deelbaar zijn door drie of het kwadrateren van die elementen. Er gebeurt alleen werk wanneer u toegang hebt tot een element in de weergave.

Elementen van een weergave zijn meestal de werkelijke elementen van het bereik dat wordt gebruikt om de weergave te maken. De weergave is meestal niet de eigenaar van de elementen; het verwijst alleen naar hen, met uitzondering van owning_view. Als u een element wijzigt, wordt dat element in het bereik gewijzigd waaruit de weergave is gemaakt. In het volgende voorbeeld ziet u dit gedrag:

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

Bereikadapters komen in veel vormen voor. Er zijn bijvoorbeeld bereikadapters waarmee u een weergave kunt produceren door:

  • Een ander bereik filteren op basis van een predicaat (filter).
  • De elementen in een bereik (transform) transformeren.
  • Een bereik splitsen (split).

Bereikadapters kunnen worden gekoppeld (samengesteld). Dat is waar de kracht en flexibiliteit van bereiken het meest duidelijk zijn. Door bereikadapters op te stellen, kunt u een kernprobleem oplossen met de vorige STL-algoritmen (Standard Template Library), namelijk dat ze niet gemakkelijk aan elkaar kunnen worden gekoppeld.

De volgende bereikadapters zijn beschikbaar in de std::views naamruimte. De std::views naamruimte is een handige alias voor std::ranges::views.

Bereikadapter Beschrijving
all C++20- Maak een weergave die verwijst naar een bereik en de bijbehorende elementen.
common C++20- Maak een weergave met dezelfde iterator- en sentinel-typen uit een bereik dat dat niet doet.
counted C++20- Maak een weergave van de eerste n elementen van een bereik, beginnend vanaf de opgegeven locatie.
drop C++20- Maak een weergave vanuit een andere weergave, waarbij het opgegeven aantal elementen van de voorzijde wordt overgeslagen.
drop_while C++20- Maak een weergave die de elementen van een bereik bevat die na de voorloopelementen die overeenkomen met de opgegeven voorwaarde, worden verwijderd.
elements C++20- Maak een weergave van de geselecteerde index in elke tuple-achtige waarde in een bereik.
empty C++20- Maak een weergave die geen elementen bevat.
filter C++20- Maak een weergave die de elementen van een bereik bevat dat overeenkomt met de opgegeven voorwaarde.
iota C++20- Maak een weergave die een reeks toenemende waarden bevat.
istream C++20- Een weergave maken over de elementen van een stroom.
join C++20- Een weergave maken waarin alle elementen van meerdere bereiken in één weergave worden gecombineerd.
keys C++20- Maak een weergave van de eerste index in elke tuple-achtige waarde in een verzameling.
lazy_split C++20- Een weergave splitsen in subbereiken op basis van een scheidingsteken.
reverse C++20- Maak een weergave van de elementen van een bereik in omgekeerde volgorde.
single C++20- Een weergave maken die één element bevat.
split C++20- Een weergave splitsen in subbereiken op basis van een scheidingsteken.
take C++20- Een weergave van de eerste n elementen maken vanuit een andere weergave.
take_while C++20- Maak een weergave die de voorloopelementen van een bereik bevat dat overeenkomt met de opgegeven voorwaarde.
transform C++20- Een weergave van getransformeerde elementen maken vanuit een andere weergave.
values C++20- Maak een weergave van de tweede index in elke tuple-achtige waarde in een verzameling.

In de vorige tabel wordt een bereikadapter meestal beschreven als het nemen van een bereik en het produceren van een weergave. Om precies te zijn, hebben bereikadapters een bereikargument dat een van de volgende opties accepteert:

  • Het cv-unqualified typemodellen viewen het argument is een rvalue of kan worden gekopieerd.
  • Wanneer u het argument doorgeeft als een lvalue, moet het modelleren range en leven zolang de weergave.
  • Wanneer u het argument doorgeeft als een rvalue, zoals bij het aanroepen owning_view, moet het modelleren range en movable.

Bereikadapterfuncties zijn doorgaans functieobjecten, die eruitzien als functieoproepen en beperkingen afdwingen voor de typen die kunnen worden doorgegeven.

U kunt bereikadapters en het resultaat van pijpbewerkingen (|) doorgeven aan code die functieobjecten verwacht. In het volgende voorbeeld wordt de weergave die de split bereikadapter maakt, doorgegeven aan de transform bereikadapter alsof deze wordt aangeroepen door een functieaanroep, omdat de transform bereikadapter een functieobject is.

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

Maak een weergave van alle elementen in een bereik.

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

Parameterwaarden

R
Het type van het onderliggende bereik.

rg
Het bereik waaruit u de weergave wilt maken.

Retourwaarde

  • Als rg dit al een weergave is, wordt er een kopie van rg.
  • Als rg dit een niet-weergave lvalue is, wordt hiernaar ref_view verwezen rg. (De levensduur van de weergave is gekoppeld aan de levensduur van rg.)
  • Als rg dit een niet-weergave rwaarde is, zoals een tijdelijk object, of het resultaat is van het doorgeven van het bereik aan std::move, een owning_view.

Hiermee std::views::all_t<decltype((rg))> haalt u het type van de geretourneerde weergave op.

Opmerkingen

Deze bereikadapter is de beste manier om een bereik te converteren naar een weergave. Een van de redenen om een weergave van een bereik te maken, is om deze tegen lage kosten door te geven, als het bereik op waarde kan duur zijn.

Het verkrijgen van een weergave voor een bereik is een handig alternatief voor het doorgeven van een zwaargewicht bereik op waarde omdat weergaven goedkoop zijn om te maken, kopiëren en vernietigen. Een mogelijke uitzondering is owning_view, een weergave die eigenaar is van het onderliggende bereik.

Over het algemeen heeft O(N) het slechtste scenario voor het vernietigen van een weergave complexiteit voor het aantal elementen in het bereik. Zelfs als u kopieën van weergave met K elementen vernietigtN, is de totale complexiteit nog steeds O(N) omdat het onderliggende bereik slechts eenmaal wordt vernietigd.

Voorbeeld: 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

Maak een weergave met hetzelfde begin-iterator- en sentinel-type uit een bereik dat mogelijk niet.

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

Parameterwaarden

R
Het type van het onderliggende bereik.

rg
Het bereik waaruit u de weergave wilt maken.

Retourwaarde

  • views::all(rg) als rg een bereik met hetzelfde iterator- en sentinel-type is.
  • common_view(views::all(rg)) als rg er verschillende iterator- en sentinel-typen zijn.

Opmerkingen

Wanneer een API vereist dat de begin-iterator en end sentinel hetzelfde type hebben en de weergave die u gebruikt, niet voldoet aan die vereiste (of u weet niet of dit het geval is), gebruikt u deze bereikadapter om een common_view. Het garandeert dat het type van de begin-iterator en het type van de end sentinel hetzelfde zijn.

Voorbeeld: common

// requires /std:c++20 or later
#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

Maak een weergave van de eerste count elementen van een bereik, beginnend vanaf de opgegeven locatie.

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

Parameterwaarden

DifferenceType
Het type van het aantal.

Iterator
Het type iterator.

count
Het aantal elementen dat in de weergave moet worden opgenomen. Moet niet-negatief zijn.

  • Als count == 0, wordt er een lege span waarde geretourneerd.
  • Als count het aantal elementen in het bereik groter is dan het aantal elementen, is het gedrag niet gedefinieerd.

it
Een iterator voor het element in het bereik om mee te beginnen. Het element waarnaar de iterator verwijst, wordt opgenomen in de gemaakte weergave.

Retourwaarde

Een span wordt geretourneerd als it dit een is contiguous_iterator voor matrices, vectoren en andere containers die hun elementen aaneengesloten opslaan. Anders wordt er een subrange geretourneerd.

Opmerkingen

De opgenomen elementen zijn [it, count).

Nadat de weergave is gemaakt, blijft het aantal elementen in de weergave hetzelfde, zelfs als het bereik dat is gemaakt op basis van wijzigingen. Als het onderliggende bereik echter verandert, kan het openen van elementen in de weergave leiden tot niet-gedefinieerd gedrag.

Voorbeeld: 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

Maak een weergave die de eerste n elementen van een bereik uitsluit.

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

Parameterwaarden

DifferenceType
Het type dat het aantal elementen beschrijft dat moet worden overgeslagen.

count
Het aantal elementen dat van de voorzijde moet rgworden verwijderd. Moet niet-negatief zijn.

  • Als count == 0, worden alle elementen in rg geretourneerd.
  • Als count het aantal elementen groter is dan het aantal elementen rg, wordt een lege weergave geretourneerd.

R
Het type bereik.

rg
Het bereik dat wordt gebruikt om de weergave te maken.

Retourwaarde

Een weergave van het onderliggende bereik, waarbij het opgegeven aantal elementen van de voorzijde is verwijderd.

Als u meer elementen opgeeft die moeten worden verwijderd dan in het onderliggende bereik, wordt er een empty_view geretourneerd.

De geretourneerde weergave is doorgaans, maar niet altijd, een specialisatie van drop_view. Dat wil zeggen:

Opmerkingen

Nadat de weergave is gemaakt, blijft het aantal elementen in de weergave hetzelfde, zelfs als de weergave is gemaakt op basis van wijzigingen. Als de onderliggende weergave echter verandert, kan het openen van elementen in de geretourneerde weergave leiden tot niet-gedefinieerd gedrag.

drop is het tegenovergestelde van take.

De code die eerder wordt weergegeven als '2)' kan worden gebruikt met de syntaxis van de pijp: collection | drop(5). Of kan worden gebruikt met syntaxis van functieoproep: drop(collection, 5) of drop(5)(collection).

Voorbeeld: 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

Maak een weergave die de elementen van een bereik bevat die na de voorloopelementen die overeenkomen met de opgegeven voorwaarde, worden verwijderd.

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

Parameterwaarden

R
Het type bereik.

predicate
De voorwaarden die bepalen welke voorloopelementen uit het bereik moeten worden verwijderd.

rg
Het onderliggende bereik waaruit u de weergave wilt maken.

Retourwaarde

Een drop_while_view die bestaat uit de elementen die behouden blijven wanneer de voorloopelementen die overeenkomen met het predicaat worden verwijderd.

Opmerkingen

Stopt met het verwijderen van elementen vanaf rg zodra het predicaat terugkeert false.

drop_while is het tegenovergestelde van take_while.

De code die eerder wordt weergegeven als '2)' kan worden gebruikt met de syntaxis van de pijp: collection | drop_while(predicate). Of kan worden gebruikt met syntaxis van functieoproep: drop_while(collection, predicate) of drop_while(predicate)(collection).

Voorbeeld: 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

Maak een elements_view, een weergave van de geselecteerde index in elke tuple-achtige waarde in een bereik. Als u bijvoorbeeld een bereik met std::tuple<string, int> waarden hebt, maakt u een elements_view van alle string elementen van elke tuple.

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

Parameterwaarden

N
De index van het element dat moet worden geselecteerd uit elke tuple-achtige waarde die in de weergave moet worden opgenomen.

R
Het type van het onderliggende bereik.

rg
Het bereik van tuple-achtige waarden waaruit u de weergave wilt maken.

Retourwaarde

Een elements_view die bestaat uit de geselecteerde index in elke tuple-achtige waarde in een verzameling.

Voorbeeld: 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

Maak een empty_view, een weergave die geen elementen bevat.

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

Parameterwaarden

T
Het type elementen in de weergave. De weergave heeft een elementtype nodig, ook al zijn er geen elementen.

Retourwaarde

Een empty_view.

Opmerkingen

Een empty_view kan handig zijn wanneer u code aanroept die een weergave vereist, maar geen van de elementen hoeft te verwerken.

Voorbeeld: empty

// requires /std:c++20 or later
#include <ranges>
#include <iostream>

int main()
{
    auto anEmptyView = std::views::empty<int>;
    bool isNotEmpty = (bool)anEmptyView;
    std::cout << boolalpha << isNotEmpty << "\n"; // false
}
false

filter

Maak een weergave die de elementen van een bereik bevat dat overeenkomt met de opgegeven voorwaarde.

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

Parameterwaarden

P
Het type predicaat.

predicate
De voorwaarden die bepalen welke elementen in het bereik moeten worden bewaard.

R
Het type van het onderliggende bereik.

rg
Het bereik waaruit u de weergave wilt maken.

Retourwaarde

Een filter_view die de elementen van een bereik bevat dat overeenkomt met het predicaat.

Opmerkingen

Als u een pijp gebruikt filter en transform samen met een pijp |gebruikt, doet u het filter eerste zodat u transform alleen de elementen die u wilt behouden.

De code die eerder wordt weergegeven als '2)' kan worden gebruikt met de syntaxis van de pijp: collection | filter(predicate). Of kan worden gebruikt met syntaxis van functieoproep: filter(collection, predicate) of filter(predicate)(collection).

Voorbeeld: 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

Maak een weergave die een reeks toenemende waarden bevat. De reeks kan worden gebonden of niet.

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

Parameterwaarden

E
Het type van de eindwaarde.

S
Het type van de beginwaarde.

startValue
De eerste waarde in de reeks.

endValue
Deze waarde is één achter de laatste waarde die zich in de reeks bevindt. Genereert bijvoorbeeld std::views::iota(0, 5) een weergave met de waarden 0,1,2,3,4.

Retourwaarde

Een iota_view reeks toenemende waarden.

Opmerkingen

Voor een niet-gebonden reeks is het gedrag niet gedefinieerd nadat de maximumwaarde van het gegevenstype is bereikt.

Voorbeeld: 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

Een weergave maken over de elementen van een stroom.

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

Parameterwaarden

str
Een stroomobject. Het type is afgeleid van een specialisatie van std::basic_istream.

Val
Het type elementen dat uit de stroom moet worden geëxtraheerd.

Retourwaarde

A basic_istream_view.

Deze bereikadapter is gelijk aan ranges::basic_istream_view<Val, typename U::char_type, typename U::traits_type>(str), waar U is het type str.

Voorbeeld: 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

Een weergave maken waarin alle elementen van meerdere bereiken in één weergave worden gecombineerd.

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

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

Parameterwaarden

R
Het type van het onderliggende bereik.

rg
Het bereik waaruit u de weergave wilt maken.

Retourwaarde

Een join_view met de elementen van alle bereiken in het onderliggende bereik.

Voorbeeld: 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.

Opmerkingen

De code die eerder wordt weergegeven als '2)' kan worden gebruikt met de syntaxis van de pijp: collection | join. Of kan worden gebruikt met de syntaxis van de functie-aanroep: join(collection).

keys

Maak een keys_view van de eerste index in elke tuple-achtige waarde in een verzameling. Dit is handig voor het extraheren van sleutels uit associatieve containers. Als u bijvoorbeeld een bereik hebt std::tuple<string, int>, maakt u een weergave die bestaat uit alle string elementen van elke tuple.

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

Parameterwaarden

R
Het type van het onderliggende bereik.

Retourwaarde

Een keys_view die bestaat uit de eerste index in elke tuple-achtige waarde in het bereik.

Voorbeeld: 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

Splits een bereik in subbereiken op basis van een scheidingsteken. Het scheidingsteken kan één element of een weergave van elementen zijn.

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

Parameterwaarden

delimiter
Eén waarde of een reeks waarden die aangeven waar het bereik moet worden gesplitst.

Pattern
Het type scheidingsteken.

R
Het type bereik dat moet worden gesplitst.

rg
Het bereik dat moet worden gesplitst.

Retourwaarde

Een lazy_split_view met een of meer subbereiken en is het resultaat van het splitsen van het oorspronkelijke bereik op delimiter.

Opmerkingen

Het scheidingsteken maakt geen deel uit van het resultaat. Als u bijvoorbeeld het bereik 1,2,3 splitst op de waarde 2, krijgt u twee subbereiken: 1 en 3.

Een gerelateerde adapter is split. De belangrijkste verschillen tussen split_view en lazy_split_view zijn:

Bekijk Kan een const bereik splitsen Bereik-iterator
split_view Nee Ondersteunt forward_range of hoger
lazy_split_view ja input_range of hoger

Liever split_view omdat het efficiënter is, tenzij u een bereik moet splitsen dat is const.

De code die eerder wordt weergegeven als '2)' kan worden gebruikt met de syntaxis van de pijp: collection | lazy_split(delimiter). Of kan worden gebruikt met syntaxis van functieoproep: lazy_split(collection, delimiter) of lazy_split(delimiter)(collection).

Voorbeeld: 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

Maak een weergave van de elementen van een bereik in omgekeerde volgorde.

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

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

Parameterwaarden

R
Het type van het onderliggende bereik dat u wilt omkeren.

rg
Het bereik om terug te keren.

Retourwaarde

Een weergave die de elementen van het onderliggende bereik in omgekeerde volgorde weergeeft. De geretourneerde weergave is doorgaans, maar niet altijd, een specialisatie van reverse_view. Dat wil zeggen:

  • Als V dit een specialisatie reverse_viewis, is het resultaat de onderliggende weergave van het argument. Een dubbele omkering is een no-op (geen bewerking).
  • Als V het formulier subrange<reverse_iterator<I>, reverse_iterator<I>>is, is het resultaat een subrange van de uitgepakte iterators. Een dubbele omkering is een no-op.
  • Anders is het resultaat een reverse_view.

Opmerkingen

De code die eerder wordt weergegeven als '2)' kan worden gebruikt met de syntaxis van de pijp: collection | reverse. Of kan worden gebruikt met de syntaxis van de functie-aanroep: reverse(collection).

Voorbeeld: 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

Maak een single_view, een weergave die één element bevat.

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

Parameterwaarden

T
Het type element in de weergave.

t
De waarde van het element dat in de weergave moet worden opgeslagen.

Retourwaarde

Een single_view met t.

Opmerkingen

Deze weergave is handig voor testdoeleinden, voor het aanroepen van code die moet worden geleverd met een weergave met ten minste één element erin.

Voorbeeld: single

// requires /std:c++20 or later
#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

Een weergave splitsen in subbereiken op basis van een scheidingsteken. Het scheidingsteken kan één element of een reeks elementen zijn.

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

Parameterwaarden

delimiter
Eén waarde of een reeks waarden die aangeven waar het bereik moet worden gesplitst.

Pattern
Het type scheidingsteken.

R
Het type van het onderliggende bereik dat moet worden gesplitst.

rg
Het bereik dat moet worden gesplitst.

Retourwaarde

Een split_view met een of meer subbereiken.

Opmerkingen

Het scheidingsteken maakt geen deel uit van het resultaat. Als u bijvoorbeeld het bereik 1,2,3 splitst op de waarde 2, krijgt u twee subbereiken: 1 en 3.

Een gerelateerde adapter is lazy_split. De belangrijkste verschillen tussen split_view en lazy_split_view zijn:

Bekijk Kan een const bereik splitsen Bereiktype
split_view Nee Ondersteunt forward_range of hoger
lazy_split_view ja Ondersteunt input_range of hoger

Liever split_view omdat het efficiënter is, tenzij u een bereik moet splitsen dat is const.

De code die eerder wordt weergegeven als '2)' kan worden gebruikt met de syntaxis van de pijp: collection | split(delimiter). Of kan worden gebruikt met syntaxis van functieoproep: split(collection, 5) of split(5)(collection).

Voorbeeld: 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

Maak een weergave die het opgegeven aantal elementen bevat dat afkomstig is van de voorkant van een bereik.

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

Parameterwaarden

R
Het type van het onderliggende bereik.

rg
Het bereik waaruit u de weergave wilt maken.

count
Het aantal elementen dat van de voorzijde moet rgworden overgenomen.

Retourwaarde

De geretourneerde weergave is doorgaans, maar niet altijd, een specialisatie van take_view. Specifiek:

Opmerkingen

Als u meer elementen opgeeft die moeten worden gebruikt dan aanwezig rgis, worden alle elementen gebruikt.

take is het tegenovergestelde van drop.

De code die eerder wordt weergegeven als '2)' kan worden gebruikt met de syntaxis van de pijp: collection | take(5). Of kan worden gebruikt met syntaxis van functieoproep: take(5, collection) of take(5)(collection).

Voorbeeld: 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

Maak een weergave die de voorloopelementen van een bereik bevat dat overeenkomt met de opgegeven voorwaarde.

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

Parameterwaarden

P
Het type predicaat.

predicate
De voorwaarden die bepalen welke voorloopelementen uit het bereik moeten worden gekopieerd.

R
Het type van het onderliggende bereik.

rg
Het bereik waaruit u de weergave wilt maken.

Retourwaarde

Een take_while_view die bestaat uit de eerste count elementen die voldoen aan de opgegeven criteria in het bereik.

Opmerkingen

Stopt met het nemen van elementen nadat rg het predicaat terugkeert false of het bereik geen elementen meer bevat.

take_while is het tegenovergestelde van drop_while.

De code die eerder wordt weergegeven als '2)' kan worden gebruikt met de syntaxis van de pijp: collection | take_while(pred). Of kan worden gebruikt met syntaxis van functieoproep: take_while(collection, pred) of take_while(pred)(collection).

Voorbeeld: 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

Maak een weergave van elementen, die elk een transformatie is van een element in het opgegeven bereik.

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

Parameterwaarden

F
Het type van het functieobject om de elementen te transformeren.

R
Het type van het onderliggende bereik.

fun
De functie waarmee de elementen worden getransformeerd.

rg
Het bereik waaruit u de weergave wilt maken.

Retourwaarde

Een transform_view die de getransformeerde elementen van rg.

Opmerkingen

In het belang van efficiëntie, wanneer u opstelt filter en transform, doet u de filter eerste, zodat u transform alleen de elementen die u wilt behouden.

De code die eerder wordt weergegeven als '2)' kan worden gebruikt met de syntaxis van de pijp: collection | transform(fun). Of kan worden gebruikt met syntaxis van functieoproep: transform(collection, fun) of transform(fun)(collection).

Voorbeeld: 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

Maak een values_view index die bestaat uit de tweede index in elke tuple-achtige waarde in een verzameling. Dit is handig voor het maken van een weergave van de waarden in een associatieve container. Als u bijvoorbeeld een bereik met std::tuple<string, int> waarden hebt, maakt u een weergave die bestaat uit alle int elementen van elke tuple.

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

Parameterwaarden

R
Het type van het onderliggende bereik.

rg
Het onderliggende bereik van tuple-achtige waarden.

Retourwaarde

Een values_view gebouwd van de tweede index in elke tuple-achtige waarde in het bereik.

Voorbeeld: 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

Aliassen van bereikadaptertypen

all_t

Geeft het type weergave weer dat all wordt geretourneerd.

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

Parameterwaarden

R
Het type van het onderliggende bereik.

Retourwaarde

Het type weergave dat all als resultaat geeft: decltype(views::all(std::declval<R>())).

Voorbeeld: 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;
}

Zie ook

<ranges>
<ranges> Concepten
Klassen weergeven