Adaptéry rozsahu
Adaptéry rozsahu vytvářejí zobrazení (jednu z tříd zobrazení v std::views
oboru názvů) z rozsahu. Místo přímého vytváření typů zobrazení doporučujeme použít adaptér. Adaptéry představují zamýšlený způsob přístupu k zobrazením. Snadněji se používají a v některých případech efektivnější než přímé vytváření instancí typů zobrazení.
Zobrazení je jednoduchý objekt, který odkazuje na prvky z rozsahu. Zobrazení může:
- Skládá se pouze z určitých prvků z rozsahu.
- Představuje transformaci prvků z rozsahu.
- Být obrácený rozsah nebo pouze první
n
prvky oblasti. - Buďte kombinací předchozích věcí.
Zobrazení je levné, O(1)
kopírovat, přiřazovat a zničit - bez ohledu na to, kolik prvků je zapojeno. Představte si následující příklad:
// 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
První adaptér rozsahu , filter
poskytuje zobrazení, které obsahuje prvky z input
, které jsou dělitelné třemi. Druhý adaptér rozsahu , transform
bere zobrazení, které obsahuje prvky dělitelné třemi a poskytuje pohled na čtverec těchto prvků.
Když adaptér rozsahu vytvoří zobrazení, neúčtují se náklady na transformaci každého prvku v rozsahu, aby toto zobrazení vytvořilo. Náklady na zpracování elementu v zobrazení se platí pouze v případech, kdy k ho přistupujete.
Vytvoření zobrazení je příprava na práci v budoucnu. V předchozím příkladu vytvoření zobrazení nemá za následek nalezení všech prvků dělitelných třemi nebo squaringem těchto prvků. Práce probíhá pouze v případě, že přistupujete k prvku v zobrazení.
Prvky zobrazení jsou obvykle skutečnými prvky oblasti použité k vytvoření zobrazení. Zobrazení obvykle nevlastní prvky; pouze odkazuje na ně, s výjimkou owning_view
. Změna elementu změní tento prvek v oblasti, ze které bylo zobrazení vytvořeno. Následující příklad ukazuje toto chování:
#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
}
}
Adaptéry rozsahu mají mnoho forem. Existují například adaptéry rozsahu, které umožňují vytvořit zobrazení podle:
- Filtrování jiné oblasti na základě predikátu (
filter
). - Transformace prvků v oblasti (
transform
). - Rozdělení oblasti (
split
).
Adaptéry rozsahu mohou být zřetězený (složené). Tady je nejvýraznější výkon a flexibilita rozsahů. Vytváření adaptérů rozsahu umožňuje překonat základní problém s předchozími algoritmy STL (Standard Template Library), což znamená, že není snadné je zřetězení dohromady.
V oboru názvů jsou k dispozici následující adaptéry rozsahu std::views
. Obor std::views
názvů je alias pohodlí pro std::ranges::views
.
Adaptér rozsahu | Popis |
---|---|
all C++20 |
Vytvořte zobrazení, které odkazuje na oblast a její prvky. |
common C++20 |
Vytvořte zobrazení se stejnými typy iterátoru a sentinelu z oblasti, která ne. |
counted C++20 |
Vytvořte zobrazení prvních n prvků rozsahu počínaje zadaným umístěním. |
drop C++20 |
Vytvořte zobrazení z jiného zobrazení a přeskočí zadaný počet prvků z přední části. |
drop_while C++20 |
Vytvořte zobrazení obsahující prvky oblasti, které zůstanou za úvodními prvky, které odpovídají zadané podmínce, se zahodí. |
elements C++20 |
Vytvořte zobrazení vybraného indexu do každé hodnoty podobné řazené kolekci členů v oblasti. |
empty C++20 |
Vytvořte zobrazení, které neobsahuje žádné prvky. |
filter C++20 |
Vytvořte zobrazení obsahující prvky oblasti, které odpovídají zadané podmínce. |
iota C++20 |
Vytvořte zobrazení, které obsahuje posloupnost rostoucích hodnot. |
istream C++20 |
Vytvořte zobrazení nad prvky datového proudu. |
join C++20 |
Vytvořte zobrazení, které kombinuje všechny prvky více oblastí do jednoho zobrazení. |
keys C++20 |
Vytvořte zobrazení prvního indexu do každé hodnoty podobné řazené kolekci členů v kolekci. |
lazy_split C++20 |
Rozdělte zobrazení na podranges na základě oddělovače. |
reverse C++20 |
Umožňuje vytvořit zobrazení prvků oblasti v obráceném pořadí. |
single C++20 |
Vytvořte zobrazení, které obsahuje jeden prvek. |
split C++20 |
Rozdělte zobrazení na podranges na základě oddělovače. |
take C++20 |
Vytvořte zobrazení prvních n prvků z jiného zobrazení. |
take_while C++20 |
Vytvořte zobrazení, které obsahuje úvodní prvky oblasti, které odpovídají zadané podmínce. |
transform C++20 |
Umožňuje vytvořit zobrazení transformovaných prvků z jiného zobrazení. |
values C++20 |
Vytvořte zobrazení druhého indexu do každé hodnoty podobné řazené kolekci členů v kolekci. |
V předchozí tabulce se adaptér rozsahu obvykle popisuje jako oblast a vytváří zobrazení. Aby byly přesné, adaptéry rozsahu mají argument rozsahu, který přijímá jednu z následujících možností:
- Modely
cv-unqualified
typůview
a argument je hodnota rvalue nebo je možné ho kopírovat. - Když předáte argument jako lvalue, musí modelovat
range
a žít tak dlouho, dokud zobrazení. - Když předáte argument jako rvalue, například při volání
owning_view
, musí modelovatrange
amovable
.
Funkce adaptéru rozsahu jsou obvykle objekty funkcí, které vypadají jako volání funkce a vynucují omezení typů, které lze předat.
Adaptéry rozsahu a výsledek operací potrubí (|
) můžete předat kódu, který očekává objekty funkce. V následujícím příkladu je zobrazení, které adaptér rozsahu split
vytvoří, předán adaptér rozsahu adaptéru transform
, jako by volání funkce, protože transform
adaptér rozsahu je objekt funkce.
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
Umožňuje vytvořit zobrazení všech prvků v oblasti.
template <ranges::viewable_range R>
constexpr ranges::view auto all(R&& rg) const noexcept;
Parametry
R
Typ podkladové oblasti.
rg
Oblast, ze které chcete vytvořit zobrazení.
Vrácená hodnota
- Pokud
rg
je již zobrazení, kopie souborurg
. - Je-li
rg
hodnota bez zobrazení lvalue,ref_view
která odkazuje narg
. (Doba života zobrazení je svázaná s životnostírg
.) - Pokud
rg
je hodnota rvalue, jako je dočasný objekt, nebo je výsledkem předání rozsahu dostd::move
, anowning_view
.
Slouží std::views::all_t<decltype((rg))>
k získání typu vráceného zobrazení.
Poznámky
Tento adaptér rozsahu je nejlepší způsob, jak převést rozsah na zobrazení. Jedním z důvodů, proč vytvořit zobrazení z rozsahu, je předat ho podle hodnoty s nízkými náklady, pokud by předání rozsahu podle hodnoty mohlo být nákladné.
Získání zobrazení pro rozsah je užitečnou alternativou k předání rozsahu těžké váhy podle hodnoty, protože zobrazení jsou levná pro vytváření, kopírování a zničení. Možnou výjimkou je owning_view
zobrazení, které vlastní podkladovou oblast.
Obecně platí, že nejhorší scénář pro zničení zobrazení má O(N)
složitost počtu prvků v rozsahu. I když zničíte K
kopie zobrazení s N
prvky, celková složitost je stále O(N)
, protože základní rozsah je zničen pouze jednou.
Příklad: 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
Vytvořte zobrazení, které má stejný počáteční iterátor a typ sentinelu z rozsahu, který nemusí.
template <ranges::viewable_range R>
constexpr ranges::view auto common(R&& rg) const noexcept;
Parametry
R
Typ podkladové oblasti.
rg
Oblast, ze které chcete vytvořit zobrazení.
Vrácená hodnota
views::all(rg)
pokudrg
je rozsah se stejným typem iterátoru a sentinelu.common_view(views::all(rg))
pokudrg
má různé typy iterátoru a sentinelu.
Poznámky
Pokud rozhraní API vyžaduje, aby počáteční iterátor a koncový sentinel měl stejný typ a zobrazení, které používáte, nesplňuje tento požadavek (nebo nevíte, jestli ano), použijte tento adaptér rozsahu common_view
k vytvoření . Zaručuje, že typ počátečního iterátoru a typu koncového sentinelu jsou stejné.
Příklad: 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
Vytvořte zobrazení prvních count
prvků oblasti počínaje zadaným umístěním.
template<class Iterator>
constexpr auto counted(Iterator&& it, iter_difference_t<Iterator> count);
Parametry
DifferenceType
Typ počtu.
Iterator
Typ iterátoru.
count
Počet prvků, které se mají zahrnout do zobrazení. Musí být nezáporná.
- Pokud
count == 0
se vrátí prázdnáspan
hodnota. - Pokud
count
je větší než počet prvků v rozsahu, chování není definováno.
it
Iterátor prvku v oblasti, který má začínat. Prvek, na který iterátor odkazuje, je součástí vytvořeného zobrazení.
Vrácená hodnota
Vrátí span
se, pokud it
je contiguous_iterator
pole, vektory a další kontejnery, které ukládají jejich prvky souvisle. subrange
V opačném případě se vrátí hodnota.
Poznámky
Zahrnuté prvky jsou [it, count)
.
Po vytvoření zobrazení zůstane počet prvků v zobrazení stejný, i když byl rozsah, který byl vytvořen ze změn. Pokud se ale základní rozsah změní, může přístup k prvkům ze zobrazení způsobit nedefinované chování.
Příklad: 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
Vytvořte zobrazení, které vyloučí první n prvků oblasti.
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, který popisuje počet prvků, které se mají přeskočit.
count
Počet prvků, které se mají vyhodit z přední části rg
. Musí být nezáporná.
- Pokud
count == 0
se vrátí všechny prvky vrg
. - Pokud
count
je větší než počet prvků vrg
, vrátí se prázdné zobrazení.
R
Typ rozsahu.
rg
Oblast, která se používá k vytvoření zobrazení.
Vrácená hodnota
Zobrazení podkladového rozsahu se zadaným počtem prvků vynechaných zepředu.
Pokud zadáte více prvků, které mají být v podkladové oblasti empty_view
, vrátí se.
Vrácené zobrazení je obvykle, ale ne vždy, specializace drop_view
. To znamená:
- Pokud
V
je specializaceempty_view
, nebo je specializacespan
,basic_string_view
iota_view
, , nebosubrange
to je obojírandom_access_range
asized_range
, výsledek je specializaceV
. - V opačném případě je
drop_view
výsledkem .
Poznámky
Po vytvoření zůstane počet prvků v zobrazení stejný i v případě, že zobrazení, které bylo vytvořeno ze změn. Pokud se ale podkladové zobrazení změní, může přístup k prvkům ve vráceném zobrazení způsobit nedefinované chování.
drop
je opakem take
.
Kód uvedený dříve jako "2)" lze použít se syntaxí svislé roury: collection | drop(5)
. Nebo se dá použít se syntaxí volání funkce: drop(collection, 5)
nebo drop(5)(collection)
.
Příklad: 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
Vytvořte zobrazení obsahující prvky oblasti, které zůstanou za úvodními prvky, které odpovídají zadané podmínce, se zahodí.
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 rozsahu.
predicate
Podmínky, které určují, které úvodní prvky se mají vypustit z rozsahu.
rg
Podkladová oblast, ze které chcete vytvořit zobrazení.
Vrácená hodnota
A drop_while_view
, který se skládá z prvků, které zůstávají, když jsou úvodní prvky, které odpovídají predikátu, vyřazeny.
Poznámky
Zastaví vyřazení prvků z rg
jakmile predikát vrátí false
.
drop_while
je opakem take_while
.
Kód uvedený dříve jako "2)" lze použít se syntaxí svislé roury: collection | drop_while(predicate)
. Nebo se dá použít se syntaxí volání funkce: drop_while(collection, predicate)
nebo drop_while(predicate)(collection)
.
Příklad: 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
Vytvořte zobrazení elements_view
vybraného indexu do každé hodnoty podobné řazené kolekci členů v oblasti. Například vzhledem k rozsahu std::tuple<string, int>
hodnot vytvořte elements_view
ze všech prvků z každé řazené kolekce členů všechny string
prvky.
template<ranges::viewable_range R, size_t N>
constexpr ranges::view auto elements<N>(R&& rg);
Parametry
N
Index prvku, který chcete vybrat z každé hodnoty podobné řazené kolekci členů, která se má zahrnout do zobrazení.
R
Typ podkladové oblasti.
rg
Rozsah hodnot řazených kolekcí členů, ze které chcete vytvořit zobrazení.
Vrácená hodnota
Ten elements_view
se skládá z vybraného indexu do každé hodnoty podobné řazené kolekci členů v kolekci.
Příklad: 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
Vytvořte zobrazení empty_view
, které neobsahuje žádné prvky.
template<class T>
inline constexpr empty_view<T> empty{};
Parametry
T
Typ prvků v zobrazení. Zobrazení potřebuje typ elementu, i když neexistují žádné prvky.
Vrácená hodnota
A empty_view
.
Poznámky
Může empty_view
být užitečné při volání kódu, který vyžaduje zobrazení, ale nemusí zpracovávat žádné jeho prvky.
Příklad: 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
Vytvořte zobrazení obsahující prvky oblasti, které odpovídají zadané podmínce.
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 predikátu.
predicate
Podmínky, které určují, které prvky mají být v rozsahu zachovány.
R
Typ podkladové oblasti.
rg
Oblast, ze které chcete vytvořit zobrazení.
Vrácená hodnota
A filter_view
, který obsahuje prvky oblasti, které odpovídají predikátu.
Poznámky
Pro efektivitu, když používáte filter
a transform
společně s potrubím |
, udělejte filter
první, abyste transform
pouze prvky, které chcete zachovat.
Kód uvedený dříve jako "2)" lze použít se syntaxí svislé roury: collection | filter(predicate)
. Nebo se dá použít se syntaxí volání funkce: filter(collection, predicate)
nebo filter(predicate)(collection)
.
Příklad: 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
Vytvořte zobrazení, které obsahuje posloupnost rostoucích hodnot. Posloupnost může být ohraničena nebo ne.
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 koncové hodnoty.
S
Typ počáteční hodnoty.
startValue
První hodnota v sekvenci.
endValue
Tato hodnota je jedna za poslední hodnotou, která bude v sekvenci. Například std::views::iota(0, 5)
vygeneruje zobrazení, které obsahuje hodnoty 0,1,2,3,4
.
Vrácená hodnota
Posloupnost iota_view
rostoucích hodnot.
Poznámky
U nevázané sekvence je chování po dosažení maximální hodnoty jeho datového typu nedefinované.
Příklad: 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
Vytvořte zobrazení nad prvky datového proudu.
template <class Val>
views::istream<Val>(str);
Parametry
str
Objekt datového proudu. Jeho typ je odvozen od specializace std::basic_istream
.
Val
Typ prvků, které se mají extrahovat z datového proudu.
Vrácená hodnota
Úloha basic_istream_view
.
Tento adaptér rozsahu je ekvivalentní ranges::basic_istream_view<Val, typename U::char_type, typename U::traits_type>(str)
, kde U
je typ str
.
Příklad: 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
Vytvořte zobrazení, které kombinuje všechny prvky více oblastí do jednoho zobrazení.
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 podkladové oblasti.
rg
Oblast, ze které chcete vytvořit zobrazení.
Vrácená hodnota
A join_view
, který obsahuje prvky všech oblastí v podkladové oblasti.
Příklad: 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.
Poznámky
Kód uvedený dříve jako "2)" lze použít se syntaxí svislé roury: collection | join
. Nebo se dá použít se syntaxí volání funkce: join(collection)
.
keys
Vytvořte keys_view
první index do každé hodnoty podobné řazené kolekci členů v kolekci. To je užitečné pro extrakci klíčů z asociativních kontejnerů. Například vzhledem k rozsahu std::tuple<string, int>
, vytvořit zobrazení, které se skládá ze všech string
prvků z každé řazené kolekce členů.
template <ranges::viewable_range R>
constexpr auto keys(R&& rg);
Parametry
R
Typ podkladové oblasti.
Vrácená hodnota
Hodnota keys_view
, která se skládá z prvního indexu do každé hodnoty podobné řazené kolekci členů v rozsahu.
Příklad: 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
Rozdělte rozsah na podranges na základě oddělovače. Oddělovač může být jeden prvek nebo zobrazení prvků.
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
Jedna hodnota nebo posloupnost hodnot, které určují, kam se má rozsah rozdělit.
Pattern
Typ oddělovače.
R
Typ rozsahu, který chcete rozdělit.
rg
Oblast, která se má rozdělit.
Vrácená hodnota
A lazy_split_view
, který obsahuje jednu nebo více dílčích uspořádání a je výsledkem rozdělení původního rozsahu na delimiter
.
Poznámky
Oddělovač není součástí výsledku. Pokud například rozdělíte rozsah 1,2,3
na hodnotu 2
, získáte dvě dílčí uspořádání: 1
a 3
.
Související adaptér je split
. Mezi [split_view](split-view-class.md) and
lazy_split_view' jsou hlavní rozdíly:
Zobrazení | Může rozdělit oblast.const |
Iterátor rozsahu |
---|---|---|
split_view |
ne | Podpora forward_range nebo vyšší |
lazy_split_view |
ano | input_range nebo vyšší |
Preferujte split_view
, protože je efektivnější, pokud není nutné rozdělit rozsah, který je const
.
Kód uvedený dříve jako "2)" lze použít se syntaxí svislé roury: collection | lazy_split(delimiter)
. Nebo se dá použít se syntaxí volání funkce: lazy_split(collection, delimiter)
nebo lazy_split(delimiter)(collection)
.
Příklad: 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
Umožňuje vytvořit zobrazení prvků oblasti v obráceném pořadí.
1) template<viewable_range R>
constexpr ranges::view auto reverse(R&& rg);
2) inline constexpr /*range adaptor closure*/ reverse();
Parametry
R
Typ podkladové oblasti, která se má vrátit zpět.
rg
Oblast, která se má vrátit zpět.
Vrácená hodnota
Zobrazení, které představuje prvky podkladového rozsahu v obráceném pořadí. Vrácené zobrazení je obvykle, ale ne vždy, specializace reverse_view
. To znamená:
- Pokud
V
je specializacereverse_view
, výsledkem je podkladové zobrazení argumentu. Dvojitá zpětná operace je operace typu no-op (žádná operace). - Pokud
V
má formulářsubrange<reverse_iterator<I>, reverse_iterator<I>>
, výsledek jesubrange
přepsaný iterátory. Dvojitý opak je no-op. - V opačném případě je
reverse_view
výsledkem .
Poznámky
Kód uvedený dříve jako "2)" lze použít se syntaxí svislé roury: collection | reverse
. Nebo se dá použít se syntaxí volání funkce: reverse(collection)
.
Příklad: 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
Vytvořte zobrazení single_view
, které obsahuje jeden prvek.
template<class T>
constexpr ranges::view auto single(T&& t);
Parametry
T
Typ prvku v zobrazení.
t
Hodnota elementu, který se má uložit v zobrazení.
Vrácená hodnota
t
Obsahuje single_view
.
Poznámky
Toto zobrazení je užitečné pro testovací účely, pro volání kódu, který je potřeba poskytnout v zobrazení, které má alespoň jeden prvek v něm.
Příklad: 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
Rozdělte zobrazení na podranges na základě oddělovače. Oddělovač může být jeden prvek nebo posloupnost prvků.
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
Jedna hodnota nebo posloupnost hodnot, které určují, kam se má rozsah rozdělit.
Pattern
Typ oddělovače.
R
Typ podkladové oblasti, která se má rozdělit.
rg
Oblast, která se má rozdělit.
Vrácená hodnota
A split_view
, která obsahuje nejméně jednu poduspořádku.
Poznámky
Oddělovač není součástí výsledku. Pokud například rozdělíte rozsah 1,2,3
na hodnotu 2
, získáte dvě dílčí uspořádání: 1
a 3
.
Související adaptér je lazy_split
. Mezi hlavními rozdíly mezi split_view
a lazy_split_view
mezi těmito jednotlivými hodnotami jsou:
Zobrazení | Může rozdělit oblast.const |
Typ rozsahu |
---|---|---|
split_view |
ne | Podpora forward_range nebo vyšší |
lazy_split_view |
ano | Podpora input_range nebo vyšší |
Preferujte split_view
, protože je efektivnější, pokud není nutné rozdělit rozsah, který je const
.
Kód uvedený dříve jako "2)" lze použít se syntaxí svislé roury: collection | split(delimiter)
. Nebo se dá použít se syntaxí volání funkce: split(collection, 5)
nebo split(5)(collection)
.
Příklad: 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
Vytvořte zobrazení, které obsahuje zadaný počet prvků převzatých z přední části rozsahu.
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 podkladové oblasti.
rg
Oblast, ze které chcete vytvořit zobrazení.
count
Početprvkůch rg
Vrácená hodnota
Vrácené zobrazení je obvykle, ale ne vždy, specializace take_view
. Konkrétně:
- Pokud
V
je specializaceempty_view
, nebo je specializacespan
,basic_string_view
iota_view
, , nebosubrange
to je obojírandom_access_range
asized_range
, výsledek je specializaceV
. - V opačném případě je
take_view
výsledkem .
Poznámky
Pokud zadáte více prvků, které se mají vzít, než existuje rg
, budou odebrány všechny prvky.
take
je opakem drop
.
Kód uvedený dříve jako "2)" lze použít se syntaxí svislé roury: collection | take(5)
. Nebo se dá použít se syntaxí volání funkce: take(5, collection)
nebo take(5)(collection)
.
Příklad: 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
Vytvořte zobrazení, které obsahuje úvodní prvky oblasti, které odpovídají zadané podmínce.
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 predikátu.
predicate
Podmínky, které určují, které úvodní prvky se mají zkopírovat z rozsahu.
R
Typ podkladové oblasti.
rg
Oblast, ze které chcete vytvořit zobrazení.
Vrácená hodnota
A take_while_view
, který se skládá z prvních count
prvků, které splňují zadaná kritéria v oblasti.
Poznámky
Přestane po návratu false
predikátu přebít prvky rg
nebo oblast prvků vyprší.
take_while
je opakem drop_while
.
Kód uvedený dříve jako "2)" lze použít se syntaxí svislé roury: collection | take_while(pred)
. Nebo se dá použít se syntaxí volání funkce: take_while(collection, pred)
nebo take_while(pred)(collection)
.
Příklad: 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
Vytvořte zobrazení prvků, z nichž každý je transformací prvku v zadaném rozsahu.
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 objektu funkce pro transformaci prvků.
R
Typ podkladové oblasti.
fun
Funkce, která transformuje prvky.
rg
Oblast, ze které chcete vytvořit zobrazení.
Vrácená hodnota
A transform_view
, který obsahuje transformované prvky rg
.
Poznámky
Z důvodu efektivity, když vytváříte filter
a transform
, udělejte filter
první, abyste transform
pouze prvky, které chcete zachovat.
Kód uvedený dříve jako "2)" lze použít se syntaxí svislé roury: collection | transform(fun)
. Nebo se dá použít se syntaxí volání funkce: transform(collection, fun)
nebo transform(fun)(collection)
.
Příklad: 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
Vytvořte values_view
, která se skládá z druhého indexu, do každé hodnoty podobné řazené kolekci členů v kolekci. To je užitečné pro zobrazení hodnot v asociativním kontejneru. Například s ohledem na rozsah std::tuple<string, int>
hodnot vytvořte zobrazení, které se skládá ze všech int
prvků z každé řazené kolekce členů.
template <range::viewable_range R>
constexpr ranges::view auto values(R&& rg);
Parametry
R
Typ podkladové oblasti.
rg
Základní rozsah hodnot řazených kolekcí členů.
Vrácená hodnota
Předdefinovaná values_view
z druhého indexu do každé hodnoty podobné řazené kolekci členů v rozsahu.
Příklad: 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 adaptéru rozsahu
all_t
Poskytuje typ zobrazení, které all
vrací.
template <ranges::viewable_range R>
using all_t = decltype(views::all(std::declval<R>()));
Parametry
R
Typ podkladové oblasti.
Vrácená hodnota
Typ zobrazení, který all
vrací: decltype(views::all(std::declval<R>()))
.
Příklad: 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;
}