Sdílet prostřednictvím


<ranges> zobrazit třídy

Zobrazení je odlehčená oblast, která odkazuje na prvky, které nevlastní (s výjimkouowning_view). Zobrazení je obvykle založeno na jiné oblasti a poskytuje jiný způsob, jak se na něj podívat, ať už tím, že ho transformuje nebo filtruje. Je to například std::views::filter zobrazení, které používá kritéria, která zadáte k výběru prvků z jiné oblasti.

Když k prvkům v zobrazení přistupujete, je to "lazily", aby se práce prováděla jenom v případě, že získáte prvek. Díky tomu je možné kombinovat nebo vytvářet zobrazení bez snížení výkonu.

Můžete například vytvořit zobrazení, které poskytuje pouze sudé prvky z rozsahu, a pak je transformovat pomocí squaringu. Práce na filtrování a transformaci se provádí pouze pro prvky, ke kterým přistupujete, a pouze v případě, že k nim přistupujete.

Zobrazení lze zkopírovat, přiřadit a zničit v konstantním čase bez ohledu na to, kolik prvků obsahuje. Je to proto, že zobrazení nevlastní prvky, na které odkazuje, takže není nutné vytvořit kopii. To je důvod, proč můžete vytvářet zobrazení bez snížení výkonu.

Zobrazení obvykle vytváříte pomocí adaptéru rozsahu. Adaptéry rozsahu představují zamýšlený způsob vytvoření zobrazení, jsou jednodušší než vytvoření instance tříd zobrazení přímo a někdy jsou efektivnější než vytvoření instance tříd zobrazení přímo. Třídy zobrazení jsou vystaveny přímo v případě, že potřebujete vytvořit vlastní typ zobrazení na základě existujícího typu zobrazení.

Tady je stručný příklad vytvoření zobrazení čtverců prvků, které jsou dělitelné třemi ve vektoru:

// 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
    }
}
0 9 36 81

Použití zobrazení za rozsahem, na jehož základě je založeno, může vést k nedefinovanýmu chování. Pokud například přidáte nebo odeberete prvky z podkladového vektoru, reverse_view nemělo by se na základě vektoru znovu použít. Úprava podkladového vektoru zneplatní iterátor kontejneru end – včetně kopie iterátoru, kterou zobrazení mohlo vytvořit.

Vzhledem k tomu, že zobrazení jsou levná k vytvoření, měli byste obecně znovu vytvořit zobrazení, pokud upravíte podkladovou oblast. Následující příklad ukazuje, jak uložit kanál zobrazení do proměnné, abyste ho mohli znovu použít.

// requires /std:c++20, or later
#include <iostream>
#include <ranges>
#include <vector>
#include <list>
#include <string_view>
#include <algorithm>

template<typename rangeType>
void show(std::string_view msg, rangeType r)
{
    std::cout << msg;
    std::ranges::for_each(r,
        [](auto e)
        {
            std::cout << e << ' ';
        });
    std::cout << '\n';
}

int main()
{
    std::vector v{ 1, 2, 3, 4 };
    show("v: ", v);

    // You can save a view pipeline
    auto rev3 = std::views::take(3) | std::views::reverse;

    show("v | rev3: ", v | rev3); // 3 2 1

    v.insert(v.begin(), 0); // v = 0 1 2 3 4
    show("v: ", v);

    // Because modifying the vector invalidates its iterators, rebuild the view.
    // We are reusing the view pipeline we saved earlier
    show("v | rev3(v): ", rev3(v));
}
v: 1 2 3 4
v | rev3: 3 2 1
v: 0 1 2 3 4
v | rev3(v): 2 1 0

Následující třídy zobrazení jsou definovány v std::ranges oboru názvů.

Zobrazení Popis
basic_istream_viewC++20 Zobrazení po sobě jdoucích prvků ze vstupního datového proudu Specializace zahrnují istream_view a wistream_view.
common_viewC++20 Přizpůsobí zobrazení, které má různé typy iterátoru nebo sentinelu, do zobrazení se stejnými typy iterátoru nebo sentinelu.
drop_viewC++20 Vytvořeno z jiného zobrazení a přeskočení prvních count prvků
drop_while_viewC++20 Vytvořeno z jiného zobrazení, přeskočení úvodních prvků, pokud je predikát blokování.
elements_viewC++20 Zobrazení vybraného indexu do každé hodnoty podobné řazené kolekci členů v kolekci Například s ohledem na rozsah std::tuple<string, int> hodnot vytvořte zobrazení, které se skládá ze všech string prvků z každé řazené kolekce členů.
empty_viewC++20 Zobrazení bez prvků
filter_viewC++20 Vyfiltruje prvky oblasti, které neodpovídají predikátu.
iota_viewC++20 Vygenerované zobrazení, které obsahuje posloupnost přírůstkových hodnot.
join_viewC++20 Kombinuje všechny prvky více oblastí do jednoho zobrazení.
keys_viewC++20 Zobrazení prvního indexu do každé hodnoty podobné řazené kolekci členů v kolekci Například pro oblast std::tuple<string, int> hodnot vytvořte zobrazení, které se skládá z string prvků z každé řazené kolekce členů.
lazy_split_viewC++20 Rozdělí zobrazení na podrangely na základě oddělovače.
owning_viewC++20 Převezme vlastnictví prvků z jiného rozsahu.
ref_viewC++20 Zobrazení, které odkazuje na prvky, které patří do jiné oblasti.
reverse_viewC++20 Představuje prvky oblasti v obráceném pořadí.
single_viewC++20 Zobrazení, které obsahuje pouze jeden prvek.
split_viewC++20 Rozdělí zobrazení na podrangely na základě oddělovače.
subrangeC++20 Zobrazení části prvků oblasti, jak je definováno počátečním iterátorem a sentinelem.
take_viewC++20 Obsahuje zadaný počet prvků převzatých z přední části rozsahu.
take_while_viewC++20 Obsahuje úvodní prvky oblasti, které odpovídají danému predikátu.
transform_viewC++20 Zobrazení podkladové sekvence po použití transformační funkce na každý prvek.
values_viewC++20 Zobrazení druhého indexu do každé hodnoty podobné řazené kolekci členů v kolekci Například pro oblast std::tuple<string, int> hodnot vytvořte zobrazení, které se skládá z int prvků z každé řazené kolekce členů.

Mnoho z těchto tříd má odpovídající adaptéry rozsahu std:views v oboru názvů, který vytváří instance z nich. Raději použijte adaptér k vytvoření zobrazení místo přímého vytváření tříd zobrazení. Adaptéry rozsahu představují zamýšlený způsob vytváření zobrazení, jsou jednodušší a v některých případech jsou efektivnější.

Zobrazení charakteristik tříd

Každé téma třídy zobrazení má za oddílem syntaxe oddíl Charakteristiky . Oddíl Charakteristiky obsahuje následující položky:

  • Adaptér rozsahu: Propojení s adaptérem rozsahu, který vytvoří zobrazení. Adaptér rozsahu obvykle používáte k vytvoření zobrazení místo přímého vytvoření třídy zobrazení, takže je zde uvedený pro usnadnění práce.

  • Základní rozsah: Zobrazení mají různé požadavky iterátoru na druh základního rozsahu, který můžou použít. Další informace o typech iterátorů najdete v hierarchii iterátoru rozsahů.

  • Zobrazit kategorii iterátoru: Kategorie iterátoru zobrazení. Když zobrazení přizpůsobí oblast, typ iterátoru pro zobrazení je obvykle stejný jako typ iterátoru podkladové oblasti. U některých zobrazení se ale může lišit. Například reverse_view má , bidirectional_iteratori když základní rozsah má random_access_iterator.

  • Typ elementu: Typ prvků, které iterátor zobrazení vrátí.

  • Velikost: Určuje, jestli zobrazení může vrátit počet prvků, na které odkazuje. Ne všechna zobrazení můžou.

  • Běžný rozsah: Určuje, jestli je zobrazení typu common_range, což znamená, že počáteční iterátor a typy sentinelů jsou stejné. Běžné rozsahy jsou užitečné pro kód před rozsahem, který funguje s páry iterátoru. Příkladem jsou konstruktory páru iterátoru pro sekvenci kontejneru, například vector(ranges::begin(x), ranges::end(x)).

  • Zapůjčený rozsah: Určuje, jestli je zobrazení zapůjčeným rozsahem. borrowed_range<T> znamená, že po zničení můžete použít iterátory T T .

    Žádný standardní kontejner není zapůjčený rozsah, protože zničení kontejneru uvolní prvky a zneplatní všechny iterátory. V takovém případě říkáme, že iterátory jsou po zničení ponechány "chvění".

    Obvykle například std::ranges::find() vrátí iterátor nalezený prvek v argumentu rozsahu. Pokud je argument rozsahu dočasným kontejnerem (rvalue), je chyba uložit vrácený iterátor a použít ho později, protože se jedná o "propletení".

    Algoritmy rozsahu, které vracejí iterátory (nebo podrangely), to dělají pouze tehdy, když jsou jejich argumenty lvalue (dočasně) nebo vypůjčené rozsahy. V opačném případě vrátí objekt, který poskytuje nápovědu std::dangling v chybových zprávách o tom, co se pokazilo, pokud jste se pokusili použít jako iterátor.

  • Je const možné iterovat: Označuje, jestli můžete iterovat instanci const zobrazení. Ne všechna const zobrazení se dají itestrovat. Pokud zobrazení není const možné iterovat, nemůžete ho iterovat for (const auto& element : as_const(theView)) ani předat funkci, která vezme const odkaz na zobrazení a pokusí se ho iterovat.

Hierarchie iterátoru rozsahů

V části Charakteristiky každého tématu třídy zobrazení se kategorie iterátoru v podkladové oblasti a kategorie iterátoru zobrazení odkazuje na druh iterátoru, který oblast/zobrazení podporuje. Existuje šest kategorií iterátorů rozsahů, které jsou identifikovány koncepty C++20. Hierarchie iterátorů rozsahu v rostoucím pořadí schopností je:

Koncept iterátoru rozsahu Popis
output_range Jen zápis, přesouvá se pouze vpřed; jednoprůchodový.
input_range Jen pro čtení se posune vpřed; jednoprůchodový.
forward_range Posune se jen vpřed; vícenásobný průchod.
bidirectional_range Může se pohybovat vpřed a dozadu; vícenásobný průchod.
random_access_range Má přístup k kolekci pomocí indexu; vícenásobný průchod.
contiguous_range Má přístup k kolekci s indexem a prvky jsou uloženy souvisle v paměti.

Obecně řečeno, iterátor má schopnost iterátorů, které před ním v tabulce předchází. Například bidirectional_range má možnosti forward_range, ale ne naopak. S výjimkou input_range, který nemá schopnost output_range , protože nemůžete napsat do input_range.

Příkaz "vyžaduje input_range nebo vyšší" znamená, že zobrazení lze použít s input_range, forward_range, bidirectional_range, random_access_range, nebo contiguous_range iterátorem, protože jsou všechny tak schopné jako input_range.

Hierarchie iterátoru rozsahů přímo souvisí s hierarchií iterátoru. Další informace najdete v tématu Koncepty iterátoru.

Viz také

<ranges>
Adaptéry rozsahu