Condividi tramite


Adattatori di intervallo

Gli adattatori di intervallo creano una visualizzazione (una delle classi View nello spazio dei std::views nomi) da un intervallo. È consigliabile usare un adattatore per creare visualizzazioni anziché creare direttamente i tipi di visualizzazione. Gli adattatori sono il modo previsto per accedere alle visualizzazioni. Sono più facili da usare e, in alcuni casi, più efficienti rispetto alla creazione diretta di istanze dei tipi di visualizzazione.

Una visualizzazione è un oggetto leggero che fa riferimento agli elementi di un intervallo. Una visualizzazione può:

  • Sono costituiti solo da determinati elementi di un intervallo.
  • Rappresenta una trasformazione di elementi da un intervallo.
  • Invertirsi o solo i primi n elementi di un intervallo.
  • Essere una combinazione delle cose precedenti.

Una visualizzazione è economica, O(1), per copiare, assegnare ed eliminare definitivamente, indipendentemente dal numero di elementi coinvolti. Si consideri l'esempio seguente:

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

Il primo adattatore di intervallo, filter, fornisce una visualizzazione che contiene gli elementi da input cui sono divisibili per tre. L'altro adattatore di intervallo, transform, accetta la visualizzazione che contiene gli elementi divisibile per tre e fornisce una visualizzazione del quadrato di tali elementi.

Quando un adattatore di intervallo produce una visualizzazione, non comporta il costo della trasformazione di ogni elemento nell'intervallo per produrre tale visualizzazione. Il costo per elaborare un elemento nella visualizzazione viene pagato solo quando si accede a tale elemento.

La creazione di una vista è la preparazione per eseguire operazioni future. Nell'esempio precedente, la creazione della vista non comporta la ricerca di tutti gli elementi divisibile per tre o squaring di tali elementi. Il lavoro avviene solo quando si accede a un elemento nella visualizzazione.

Gli elementi di una visualizzazione sono in genere gli elementi effettivi dell'intervallo utilizzato per creare la vista. La vista in genere non è proprietaria degli elementi; si riferisce solo a essi, ad eccezione di owning_view. La modifica di un elemento modifica l'elemento nell'intervallo da cui è stata creata la visualizzazione. L'esempio seguente illustra questo comportamento:

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

Gli adattatori di intervallo sono disponibili in molte forme. Ad esempio, sono disponibili adattatori di intervallo che consentono di produrre una visualizzazione in base a:

  • Filtro di un altro intervallo basato su un predicato (filter).
  • Trasformazione degli elementi in un intervallo (transform).
  • Divisione di un intervallo (split).

Gli adattatori di intervallo possono essere concatenati (composti). Ecco dove la potenza e la flessibilità degli intervalli sono più evidenti. La composizione degli adattatori di intervallo consente di risolvere un problema principale con gli algoritmi STL (Standard Template Library) precedenti, ovvero che non sono facili da concatenare.

Gli adattatori di intervallo seguenti sono disponibili nello spazio dei std::views nomi . Lo std::views spazio dei nomi è un alias pratico per std::ranges::views.

Adattatore di intervallo Descrizione
allC++20 Creare una vista che fa riferimento a un intervallo e ai relativi elementi.
commonC++20 Creare una vista con gli stessi tipi di iteratore e sentinel da un intervallo che non lo fa.
countedC++20 Creare una visualizzazione dei primi n elementi di un intervallo, a partire dalla posizione specificata.
dropC++20 Creare una visualizzazione da un'altra visualizzazione, ignorando il numero specificato di elementi dalla parte anteriore.
drop_whileC++20 Creare una visualizzazione contenente gli elementi di un intervallo che rimangono dopo l'eliminazione degli elementi iniziali che corrispondono alla condizione specificata.
elementsC++20 Creare una vista dell'indice selezionato in ogni valore simile a una tupla in un intervallo.
emptyC++20 Creare una vista senza elementi.
filterC++20 Creare una vista contenente gli elementi di un intervallo che corrispondono alla condizione specificata.
iotaC++20 Creare una vista contenente una sequenza di valori crescenti.
istreamC++20 Creare una visualizzazione sugli elementi di un flusso.
joinC++20 Creare una visualizzazione che combina tutti gli elementi di più intervalli in una singola visualizzazione.
keysC++20 Creare una vista del primo indice in ogni valore simile a una tupla in una raccolta.
lazy_splitC++20 Dividere una visualizzazione in intervalli secondari in base a un delimitatore.
reverseC++20 Creare una visualizzazione degli elementi di un intervallo in ordine inverso.
singleC++20 Creare una vista contenente un elemento.
splitC++20 Dividere una visualizzazione in intervalli secondari in base a un delimitatore.
takeC++20 Creare una visualizzazione dei primi n elementi da un'altra visualizzazione.
take_whileC++20 Creare una vista contenente gli elementi iniziali di un intervallo che corrispondono alla condizione specificata.
transformC++20 Creare una visualizzazione di elementi trasformati da un'altra visualizzazione.
valuesC++20 Creare una vista del secondo indice in ogni valore simile a una tupla in una raccolta.

Nella tabella precedente, un adattatore di intervallo viene in genere descritto come accettare un intervallo e produrre una vista. Per essere precisi, gli adattatori di intervallo hanno un argomento di intervallo che accetta uno dei seguenti elementi:

  • Il cv-unqualified tipo modella viewe l'argomento è un rvalue o è copiabile.
  • Quando si passa l'argomento come lvalue, deve modellare range e vivere finché la vista.
  • Quando si passa l'argomento come rvalue, ad esempio quando si chiama owning_view, deve modellare range e movable.

Le funzioni di adattatore di intervallo sono in genere oggetti funzione, che hanno un aspetto simile alle chiamate di funzione e applicano vincoli sui tipi che possono essere passati.

È possibile passare adattatori di intervallo e il risultato delle operazioni pipe (|) al codice che prevede oggetti funzione. Nell'esempio seguente, la visualizzazione creata dall'adattatore split di intervallo viene passata all'adattatore transform di intervallo come se fosse una chiamata di funzione, perché l'adattatore transform di intervallo è un oggetto funzione.

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

Creare una visualizzazione di tutti gli elementi in un intervallo.

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

Parametri

R
Tipo dell'intervallo sottostante.

rg
Intervallo da cui creare la vista.

Valore restituito

  • Se rg è già una visualizzazione, una copia di rg.
  • Se rg è un lvalue non view, un oggetto ref_view che fa riferimento a rg. (La durata della visualizzazione è associata alla durata di rg.)
  • Se rg è un rvalue non visualizzazione, ad esempio un oggetto temporaneo o è il risultato del passaggio dell'intervallo a std::move, un oggetto owning_view.

Usare std::views::all_t<decltype((rg))> per ottenere il tipo della visualizzazione restituita.

Osservazioni:

Questo adattatore di intervallo è il modo migliore per convertire un intervallo in una visualizzazione. Un motivo per creare una visualizzazione da un intervallo consiste nel passarlo per valore a basso costo, se il passaggio dell'intervallo per valore potrebbe essere costoso.

Ottenere una visualizzazione per un intervallo è un'alternativa utile al passaggio di un intervallo di pesi massimi per valore perché le visualizzazioni sono poco costose per creare, copiare e distruggere. Un'eccezione possibile è owning_view, ovvero una vista proprietaria dell'intervallo sottostante.

In generale, lo scenario peggiore per l'eliminazione di una visualizzazione presenta O(N) complessità per il numero di elementi nell'intervallo. Anche se si eliminano K copie di visualizzazione con N elementi, la complessità totale è ancora O(N) perché l'intervallo sottostante viene eliminato una sola volta.

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

Creare una vista con lo stesso iteratore iniziale e lo stesso tipo di sentinel da un intervallo che potrebbe non essere.

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

Parametri

R
Tipo dell'intervallo sottostante.

rg
Intervallo da cui creare la vista.

Valore restituito

  • views::all(rg) se rg è un intervallo con lo stesso tipo di iteratore e sentinel.
  • common_view(views::all(rg)) se rg ha tipi di iteratore e sentinel diversi.

Osservazioni:

Quando un'API richiede che l'iteratore iniziale e l'endpoint sentinel abbiano lo stesso tipo e che la visualizzazione in uso non soddisfi tale requisito (o non si sa se lo fa), usare questo adattatore di intervallo per creare un oggetto common_view. Garantisce che il tipo dell'iteratore iniziale e il tipo di sentinel finale siano gli stessi.

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

Creare una visualizzazione dei primi count elementi di un intervallo, a partire dalla posizione specificata.

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

Parametri

DifferenceType
Tipo del conteggio.

Iterator
Tipo dell'iteratore.

count
Numero di elementi da includere nella visualizzazione. Deve essere non negativo.

  • Se count == 0, viene restituito un valore vuoto span .
  • Se count è maggiore del numero di elementi nell'intervallo, il comportamento non è definito.

it
Iteratore dell'elemento nell'intervallo da cui iniziare. L'elemento a cui punta l'iteratore è incluso nella visualizzazione creata.

Valore restituito

Viene span restituito se it è un contiguous_iterator oggetto per matrici, vettori e altri contenitori che archiviano i relativi elementi in modo contiguo. In caso contrario, viene restituito un oggetto subrange .

Osservazioni:

Gli elementi inclusi sono [it, count).

Dopo aver creato la visualizzazione, il numero di elementi nella visualizzazione rimane invariato, anche se l'intervallo creato dalle modifiche. Tuttavia, se l'intervallo sottostante cambia, l'accesso agli elementi dalla visualizzazione potrebbe comportare un comportamento indefinito.

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

Creare una vista che esclude i primi n elementi di un intervallo.

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

Parametri

DifferenceType
Tipo che descrive il numero di elementi da ignorare.

count
Numero di elementi da eliminare dalla parte anteriore di rg. Deve essere non negativo.

  • Se count == 0, vengono restituiti tutti gli elementi in rg .
  • Se count è maggiore del numero di elementi in rg, viene restituita una visualizzazione vuota.

R
Tipo dell'intervallo.

rg
Intervallo utilizzato per creare la visualizzazione.

Valore restituito

Visualizzazione dell'intervallo sottostante, con il numero specificato di elementi eliminati dalla parte anteriore.

Se si specificano più elementi da eliminare rispetto all'intervallo sottostante, viene restituito un oggetto empty_view .

La vista restituita è in genere, ma non sempre, una specializzazione di drop_view. Ovvero:

Osservazioni:

Dopo la creazione, il numero di elementi nella visualizzazione rimane invariato anche se la visualizzazione creata dalle modifiche. Tuttavia, se la visualizzazione sottostante cambia, l'accesso agli elementi nella visualizzazione restituita potrebbe comportare un comportamento non definito.

drop è l'opposto di take.

Il codice illustrato in precedenza come "2)" può essere usato con la sintassi della pipe: collection | drop(5). Oppure può essere usato con la sintassi delle chiamate di funzione: drop(collection, 5) o drop(5)(collection).

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

Creare una visualizzazione contenente gli elementi di un intervallo che rimangono dopo l'eliminazione degli elementi iniziali che corrispondono alla condizione specificata.

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

Parametri

R
Tipo dell'intervallo.

predicate
Condizioni che determinano quali elementi iniziali eliminare dall'intervallo.

rg
Intervallo sottostante da cui creare la vista.

Valore restituito

Oggetto drop_while_view costituito dagli elementi che rimangono quando vengono eliminati gli elementi iniziali che corrispondono al predicato.

Osservazioni:

Interrompe l'eliminazione di elementi da rg non appena il predicato restituisce false.

drop_while è l'opposto di take_while.

Il codice illustrato in precedenza come "2)" può essere usato con la sintassi della pipe: collection | drop_while(predicate). Oppure può essere usato con la sintassi delle chiamate di funzione: drop_while(collection, predicate) o drop_while(predicate)(collection).

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

Creare un elements_viewoggetto , ovvero una vista dell'indice selezionato in ogni valore simile a una tupla in un intervallo. Ad esempio, dato un intervallo di std::tuple<string, int> valori, creare un elements_view oggetto di tutti gli string elementi di ogni tupla.

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

Parametri

N
Indice dell'elemento da selezionare da ogni valore simile a una tupla da includere nella vista.

R
Tipo dell'intervallo sottostante.

rg
Intervallo di valori simili a tuple da cui creare la vista.

Valore restituito

Oggetto elements_view costituito dall'indice selezionato in ogni valore simile a una tupla in una raccolta.

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

Creare un oggetto empty_view, ovvero una vista senza elementi.

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

Parametri

T
Tipo degli elementi nella visualizzazione. La vista richiede un tipo di elemento, anche se non sono presenti elementi.

Valore restituito

Oggetto empty_view.

Osservazioni:

Un empty_view può essere utile quando si chiama il codice che richiede una visualizzazione, ma non è necessario elaborare alcun elemento.

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

Creare una vista contenente gli elementi di un intervallo che corrispondono alla condizione specificata.

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

Parametri

P
Tipo del predicato.

predicate
Condizioni che determinano quali elementi mantenere nell'intervallo.

R
Tipo dell'intervallo sottostante.

rg
Intervallo da cui creare la vista.

Valore restituito

Oggetto filter_view contenente gli elementi di un intervallo che corrispondono al predicato.

Osservazioni:

Per motivi di efficienza, quando si usa filter e insieme a una pipe |, eseguire la filter prima in modo che solo transform gli elementi che si intende transform mantenere.

Il codice illustrato in precedenza come "2)" può essere usato con la sintassi della pipe: collection | filter(predicate). Oppure può essere usato con la sintassi delle chiamate di funzione: filter(collection, predicate) o filter(predicate)(collection).

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

Creare una vista contenente una sequenza di valori crescenti. La sequenza può essere delimitata o meno.

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

Parametri

E
Tipo del valore finale.

S
Tipo del valore iniziale.

startValue
Primo valore nella sequenza.

endValue
Questo valore è passato dall'ultimo valore che sarà nella sequenza. Ad esempio, std::views::iota(0, 5) genera una vista con i valori 0,1,2,3,4.

Valore restituito

Oggetto iota_view di una sequenza di valori crescenti.

Osservazioni:

Per una sequenza non associato, il comportamento non è definito dopo il raggiungimento del valore massimo del relativo tipo di dati.

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

Creare una visualizzazione sugli elementi di un flusso.

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

Parametri

str
Oggetto di flusso. Il tipo è derivato da una specializzazione di std::basic_istream.

Val
Tipo degli elementi da estrarre dal flusso.

Valore restituito

Un oggetto basic_istream_view.

Questo adattatore di intervallo equivale a ranges::basic_istream_view<Val, typename U::char_type, typename U::traits_type>(str), dove U è il tipo di str.

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

Creare una visualizzazione che combina tutti gli elementi di più intervalli in una singola visualizzazione.

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

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

Parametri

R
Tipo dell'intervallo sottostante.

rg
Intervallo da cui creare la vista.

Valore restituito

Oggetto join_view contenente gli elementi di tutti gli intervalli nell'intervallo sottostante.

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

Osservazioni:

Il codice illustrato in precedenza come "2)" può essere usato con la sintassi della pipe: collection | join. In alternativa, può essere usato con la sintassi delle chiamate di funzione: join(collection).

keys

Creare un keys_view oggetto del primo indice in ogni valore simile a una tupla in una raccolta. Ciò è utile per estrarre le chiavi dai contenitori associativi. Ad esempio, dato un intervallo di std::tuple<string, int>, creare una vista costituita da tutti gli string elementi di ogni tupla.

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

Parametri

R
Tipo dell'intervallo sottostante.

Valore restituito

Oggetto keys_view costituito dal primo indice in ogni valore di tupla nell'intervallo.

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

Dividere un intervallo in intervalli secondari in base a un delimitatore. Il delimitatore può essere un singolo elemento o una visualizzazione di elementi.

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

Parametri

delimiter
Valore singolo o sequenza di valori che specificano dove suddividere l'intervallo.

Pattern
Tipo del delimitatore.

R
Tipo dell'intervallo da dividere.

rg
Intervallo da dividere.

Valore restituito

Oggetto lazy_split_view contenente uno o più intervalli secondari ed è il risultato della divisione dell'intervallo originale in delimiter.

Osservazioni:

Il delimitatore non fa parte del risultato. Ad esempio, se si divide l'intervallo 1,2,3 sul valore 2, si ottengono due intervalli secondari: 1 e 3.

Un adattatore correlato è split. Le differenze principali tra [split_view](split-view-class.md) and lazy_split_view' sono:

Visualizza Può dividere un const intervallo Iteratore di intervallo
split_view no Supporta forward_range o versione successiva
lazy_split_view yes input_range o superiore

Preferisce split_view perché è più efficiente, a meno che non sia necessario dividere un intervallo che sia const.

Il codice illustrato in precedenza come "2)" può essere usato con la sintassi della pipe: collection | lazy_split(delimiter). Oppure può essere usato con la sintassi delle chiamate di funzione: lazy_split(collection, delimiter) o lazy_split(delimiter)(collection).

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

Creare una visualizzazione degli elementi di un intervallo in ordine inverso.

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

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

Parametri

R
Tipo dell'intervallo sottostante da invertire.

rg
Intervallo da invertire.

Valore restituito

Visualizzazione che presenta gli elementi dell'intervallo sottostante in ordine inverso. La vista restituita è in genere, ma non sempre, una specializzazione di reverse_view. Ovvero:

  • Se V è una specializzazione di reverse_view, il risultato è la visualizzazione sottostante dell'argomento. Un doppio inverso è un no-op (nessuna operazione).
  • Se V ha il formato subrange<reverse_iterator<I>, reverse_iterator<I>>, il risultato è uno subrange degli iteratori non compressi. Un doppio inverso è un no-op.
  • In caso contrario, il risultato è .reverse_view

Osservazioni:

Il codice illustrato in precedenza come "2)" può essere usato con la sintassi della pipe: collection | reverse. In alternativa, può essere usato con la sintassi delle chiamate di funzione: reverse(collection).

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

Creare un single_viewoggetto , ovvero una vista contenente un elemento.

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

Parametri

T
Tipo dell'elemento nella visualizzazione.

t
Valore dell'elemento da archiviare nella visualizzazione.

Valore restituito

Oggetto single_view contenente t.

Osservazioni:

Questa visualizzazione è utile a scopo di test, per chiamare il codice che deve essere fornito con una visualizzazione che include almeno un elemento.

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

Dividere una visualizzazione in intervalli secondari in base a un delimitatore. Il delimitatore può essere un singolo elemento o una sequenza di elementi.

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

Parametri

delimiter
Valore singolo o sequenza di valori che specificano dove suddividere l'intervallo.

Pattern
Tipo del delimitatore.

R
Tipo dell'intervallo sottostante da dividere.

rg
Intervallo da dividere.

Valore restituito

Oggetto split_view contenente uno o più intervalli secondari.

Osservazioni:

Il delimitatore non fa parte del risultato. Ad esempio, se si divide l'intervallo 1,2,3 sul valore 2, si ottengono due intervalli secondari: 1 e 3.

Un adattatore correlato è lazy_split. Le principali differenze tra split_view e lazy_split_view sono:

Visualizza Può dividere un const intervallo Tipo di intervallo
split_view no Supporta forward_range o versione successiva
lazy_split_view yes Supporta input_range o versione successiva

Preferisce split_view perché è più efficiente, a meno che non sia necessario dividere un intervallo che sia const.

Il codice illustrato in precedenza come "2)" può essere usato con la sintassi della pipe: collection | split(delimiter). Oppure può essere usato con la sintassi delle chiamate di funzione: split(collection, 5) o split(5)(collection).

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

Creare una visualizzazione che contiene il numero specificato di elementi ricavati dalla parte anteriore di un intervallo.

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

Parametri

R
Tipo dell'intervallo sottostante.

rg
Intervallo da cui creare la vista.

count
Numero di elementi da accettare dalla parte anteriore di rg.

Valore restituito

La vista restituita è in genere, ma non sempre, una specializzazione di take_view. In particolare:

Osservazioni:

Se si specificano più elementi da accettare rispetto all'esistenza in rg, vengono acquisiti tutti gli elementi.

take è l'opposto di drop.

Il codice illustrato in precedenza come "2)" può essere usato con la sintassi della pipe: collection | take(5). Oppure può essere usato con la sintassi delle chiamate di funzione: take(5, collection) o take(5)(collection).

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

Creare una vista contenente gli elementi iniziali di un intervallo che corrispondono alla condizione specificata.

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

Parametri

P
Tipo del predicato.

predicate
Condizioni che determinano quali elementi iniziali copiare dall'intervallo.

R
Tipo dell'intervallo sottostante.

rg
Intervallo da cui creare la vista.

Valore restituito

Oggetto take_while_view costituito dai primi count elementi che soddisfano i criteri specificati nell'intervallo.

Osservazioni:

Interrompe l'acquisizione di elementi da rg dopo che il predicato restituisce false o l'intervallo esaurisce gli elementi.

take_while è l'opposto di drop_while.

Il codice illustrato in precedenza come "2)" può essere usato con la sintassi della pipe: collection | take_while(pred). Oppure può essere usato con la sintassi delle chiamate di funzione: take_while(collection, pred) o take_while(pred)(collection).

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

Creare una visualizzazione degli elementi, ognuno dei quali è una trasformazione di un elemento nell'intervallo specificato.

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

Parametri

F
Tipo dell'oggetto funzione da trasformare gli elementi.

R
Tipo dell'intervallo sottostante.

fun
Funzione che trasforma gli elementi.

rg
Intervallo da cui creare la vista.

Valore restituito

Oggetto transform_view contenente gli elementi trasformati di rg.

Osservazioni:

Per motivi di efficienza, quando si compone filter e transform, fare il filter primo in modo che solo transform gli elementi che si intende mantenere.

Il codice illustrato in precedenza come "2)" può essere usato con la sintassi della pipe: collection | transform(fun). Oppure può essere usato con la sintassi delle chiamate di funzione: transform(collection, fun) o transform(fun)(collection).

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

Creare un values_view oggetto costituito dal secondo indice in ogni valore simile a una tupla in una raccolta. Ciò è utile per visualizzare i valori in un contenitore associativo. Ad esempio, dato un intervallo di std::tuple<string, int> valori, creare una vista costituita da tutti gli int elementi di ogni tupla.

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

Parametri

R
Tipo dell'intervallo sottostante.

rg
Intervallo sottostante di valori simili a tuple.

Valore restituito

Oggetto values_view compilato dal secondo indice in ogni valore simile a una tupla nell'intervallo.

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

Alias del tipo di adattatore di intervallo

all_t

Fornisce il tipo di visualizzazione restituito all .

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

Parametri

R
Tipo dell'intervallo sottostante.

Valore restituito

Tipo della vista che all restituisce: decltype(views::all(std::declval<R>())).

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

Vedi anche

<ranges>
<ranges> Concetti
Visualizzare le classi