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 |
---|---|
all C++20 |
Utwórz widok odwołujący się do zakresu i jego elementów. |
common C++20 |
Utwórz widok z tym samymi typami iteratora i sentynel z zakresu, który nie jest. |
counted C++20 |
Utwórz widok pierwszych n elementów zakresu, zaczynając od określonej lokalizacji. |
drop C++20 |
Utwórz widok z innego widoku, pomijając określoną liczbę elementów z przodu. |
drop_while C++20 |
Utwórz widok zawierający elementy zakresu, które pozostają po porzuceniu elementów wiodących, które pasują do określonego warunku. |
elements C++20 |
Utwórz widok wybranego indeksu w każdej wartości podobnej do krotki w zakresie. |
empty C++20 |
Utwórz widok, który nie zawiera żadnych elementów. |
filter C++20 |
Utwórz widok zawierający elementy zakresu zgodnego z określonym warunkiem. |
iota C++20 |
Utwórz widok zawierający sekwencję rosnących wartości. |
istream C++20 |
Utwórz widok nad elementami strumienia. |
join C++20 |
Utwórz widok, który łączy wszystkie elementy wielu zakresów w jeden widok. |
keys C++20 |
Utwórz widok pierwszego indeksu w każdej wartości podobnej do krotki w kolekcji. |
lazy_split C++20 |
Podziel widok na podgrupy na podstawie ogranicznika. |
reverse C++20 |
Utwórz widok elementów zakresu w odwrotnej kolejności. |
single C++20 |
Utwórz widok zawierający jeden element. |
split C++20 |
Podziel widok na podgrupy na podstawie ogranicznika. |
take C++20 |
Utwórz widok pierwszych n elementów z innego widoku. |
take_while C++20 |
Utwórz widok zawierający wiodące elementy zakresu zgodnego z określonym warunkiem. |
transform C++20 |
Utwórz widok przekształconych elementów z innego widoku. |
values C++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-unqualified
view
typó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_view
metody , musi ona modelowaćrange
imovable
.
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, kopiarg
elementu . - Jeśli
rg
element jest wartością lvalue inną niż widok,ref_view
element odwołuje się dorg
. (Okres istnienia widoku jest powiązany z okresemrg
istnienia . - Jeśli
rg
jest wartością rvalue inną niż widok, taką jak obiekt tymczasowy, lub jest wynikiem przekazania zakresu dostd::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ślirg
jest zakresem z tym samym iteratorem i typem sentinel.common_view(views::all(rg))
jeślirg
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_view
obiekt . 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 == 0
zostanie zwrócona wartość , zostanie zwrócona pustaspan
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 == 0
zwracane są wszystkie elementy wrg
pliku. - Jeśli
count
wartość jest większa niż liczba elementów w elemecierg
, 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:
- Jeśli
V
jest specjalizacją , lub jest specjalizacjąspan
empty_view
,basic_string_view
, lubiota_view
subrange
jest zarównorandom_access_range
isized_range
, wynikiem jest specjalizacjaV
. - W przeciwnym razie wynik to
drop_view
.
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 false
wartość .
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_view
string
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_view
klasy , wynikiem jest widok podstawowy argumentu. Podwójna odwrotność jest operacją no-op (bez operacji). - Jeśli
V
ma formularzsubrange<reverse_iterator<I>, reverse_iterator<I>>
, wynikiem jestsubrange
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 t
element .
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:
- Jeśli
V
jest specjalizacją , lub jest specjalizacjąspan
empty_view
,basic_string_view
, lubiota_view
subrange
jest zarównorandom_access_range
isized_range
, wynikiem jest specjalizacjaV
. - W przeciwnym razie wynik to
take_view
.
Uwagi
Jeśli określisz więcej elementów do podjęcia niż istnieje w rg
elemecie , 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ż
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla