Megosztás a következőn keresztül:


Iterator fogalmak

A fogalmak egy C++20 nyelvi funkció, amely a fordításkor korlátozza a sablonparamétereket. Segítenek megelőzni a helytelen sablon-példányosítást, olvasható formában megadni a sablon argumentumkövetelményeit, és tömörebb sablonokkal kapcsolatos fordítóhibákat biztosítanak.

Tekintse meg az alábbi példát, amely egy olyan koncepciót határoz meg, amely megakadályozza a sablon példányosítását olyan típussal, amely nem támogatja az osztást:

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

// Definition of dividable concept which requires 
// that arguments a & b of type T support division
template <typename T>
concept dividable = requires (T a, T b)
{
    a / b;
};

// Apply the concept to a template.
// The template will only be instantiated if argument T supports division.
// This prevents the template from being instantiated with types that don't support division.
// This could have been applied to the parameter of a template function, but because
// most of the concepts in the <ranges> library are applied to classes, this form is demonstrated.
template <class T> requires dividable<T>
class DivideEmUp
{
public:
    T Divide(T x, T y)
    {
        return x / y;
    }
};

int main()
{
    DivideEmUp<int> dividerOfInts;
    std::cout << dividerOfInts.Divide(6, 3); // outputs 2
    // The following line will not compile because the template can't be instantiated 
    // with char* because char* can be divided
    DivideEmUp<char*> dividerOfCharPtrs; // compiler error: cannot deduce template arguments 
}

Amikor átadja a fordítókapcsolót /diagnostics:caret a Visual Studio 2022 17.4-es előzetes verziójának 4-es vagy újabb verziójára, a tévesnek értékelt fogalom dividable<char*> hibája közvetlenül a sikertelen kifejezéskövetelményre (a / b) mutat.

Az iterátor fogalmai a std névtérben vannak definiálva, és a <iterator> fejlécfájlban vannak deklarálva. Ezeket a tartományadafótorok, nézetek stb. deklarációiban használják.

Az iterátoroknak hat kategóriája van. Közvetlenül kapcsolódnak a Tartomány fogalmak alatt felsorolt tartományok kategóriáihoz.

A kapacitás növelése érdekében az alábbi iterátorfogalmak jelennek meg. input_or_output_iterator a képességhierarchia alsó végén található, és contiguous_iterator a felső szinten van. A hierarchia magasabb iterátorai általában az alacsonyabbak helyett használhatók, de fordítva nem. Például egy random_access_iterator iterátor használható egy forward_iteratorhelyett, de nem fordítva. Kivétel ez alól, input_iteratoramely nem használható output_iterator , mert nem tud írni.

Az iterátorhierarchia diagramja. input_or_output_iterator a bázis. input_iterator és output_iterator finomító input_or_output_iterator jelennek meg. forward_iterator következik, és input_iterator és output_iterator is finomít. bidirectional_iterator pontosítja forward_iterator. random_access_iterator pontosítja bidirectional_iterator. Végül contiguous_iterator finomítja random_access_iterator

A következő táblázatban a "Multi-pass" azt jelenti, hogy az iterátor többször is meg tudja-e vizsgálni ugyanazt az elemet. Ez lehet például egy többátjárós iterátor, vector::iterator mert másolatot készíthet az iterátorról, elolvashatja a gyűjtemény elemeit, majd visszaállíthatja az iterátort a másolatban lévő értékre, és újra megtekintheti ugyanazokat az elemeket. Ha egy iterátor egyirányú, csak egyszer tekintheti meg a gyűjtemény elemeit.

A következő táblázatban a "Példatípusok" a koncepciónak megfelelő gyűjteményekre/iterátorokra vonatkozik.

Iterátor fogalma Leírás Irány Olvasás/írás Többlépéses Példatípusok
input_or_output_iterator C++20 Az iterátor fogalmának osztályozása. Előre Olvasás/írás Nem istream_iterator, ostream_iterator
output_iterator C++20 Egy iterátort ad meg, amelybe írhat. Előre Írj! Nem ostream, inserter
input_iterator C++20 Egy olyan iterátort ad meg, amelyből egyszer olvashat. Előre Olvasás Nem istream, istreambuf_iterator
forward_iterator C++20 Olyan iterátort ad meg, amely többször is képes olvasni (és esetleg írni). Előre Olvasás/írás igen vector, list
bidirectional_iterator C++20 Olyan iterátort ad meg, amelyet előre és hátra is olvashat és írhat. Előre vagy vissza Olvasás/írás igen list, set, multiset, map, és multimap.
random_access_iterator C++20 Egy iterátort ad meg, amelyet index alapján olvashat és írhat. Előre vagy vissza Olvasás/írás igen \, \, \
contiguous_iterator C++20 Olyan iterátort ad meg, amelynek elemei szekvenciálisak a memóriában, azonos méretűek, és mutató aritmetikai használatával érhetők el. Előre vagy vissza Olvasás/írás igen array, , vectorstring.

Az iterátor egyéb fogalmai a következők:

Iterátor fogalma Leírás
sentinel_for C++20 Azt adja meg, hogy egy típus egy iterátortípus sentinelje.
sized_sentinel_for C++20 Megadja, hogy egy iterátor és annak sentinelje kivonható (használatával -) az állandó idő különbségének megkereséséhez.

bidirectional_iterator

A A bidirectional_iterator támogatja az olvasást és az írást előre és hátra.

template<class I>
concept bidirectional_iterator =
    forward_iterator<I> &&
    derived_from<ITER_CONCEPT(I), bidirectional_iterator_tag> &&
    requires(I i) {
        {--i} -> same_as<I&>;
        {i--} -> same_as<I>;
};

Paraméterek

I
Az iterátor, amely ellenőrzi, hogy ez egy bidirectional_iterator.

Megjegyzések

Az A bidirectional_iterator rendelkezik a képességekkel forward_iterator, de visszafelé is képes iterálni.

Néhány példa a tárolókra, amelyek felhasználhatók a következőkkelbidirectional_iterator: , set, multiset, map, multimapés vector.list

Példa: bidirectional_iterator

Az alábbi példa a koncepciót használja annak bidirectional_iterator megjelenítésére, hogy vector<int> rendelkezik a következővel bidirectional_iterator:

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

int main()
{
    std::cout << std::boolalpha << std::bidirectional_iterator<std::vector<int>::iterator> << '\n'; // outputs "true"

    // another way to test
    std::vector<int> v = {0,1,2};
    std::cout << std::boolalpha << std::contiguous_iterator<decltype(v)::iterator>; // outputs true
}

contiguous_iterator

Olyan iterátort ad meg, amelynek elemei szekvenciálisak a memóriában, azonos méretűek, és mutató aritmetikai használatával érhetők el.

template<class I>
    concept contiguous_iterator =
        random_access_iterator<I> &&
        derived_from<ITER_CONCEPT(I), contiguous_iterator_tag> &&
        is_lvalue_reference_v<iter_reference_t<I>> &&
        same_as<iter_value_t<I>, remove_cvref_t<iter_reference_t<I>>> &&
        requires(const I& i) {
            { to_address(i) } -> same_as<add_pointer_t<iter_reference_t<I>>>;
        };

Paraméterek

I
A tesztelni kívánt típus, amely ellenőrzi, hogy ez egy contiguous_iterator.

Megjegyzések

A contiguous_iterator mutató aritmetikai használatával érhető el, mivel az elemek egymás után vannak elhelyezve a memóriában, és azonos méretűek. Néhány példa a következőkre contiguous_iterator : array, vectorés string.

Példa: contiguous_iterator

Az alábbi példa a contiguous_iterator koncepciót használja annak bemutatására, hogy az egyik vector<int> rendelkezik a következővel contiguous_iterator:

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

int main()
{
    // Show that vector<int> has a contiguous_iterator
    std::cout << std::boolalpha << std::contiguous_iterator<std::vector<int>::iterator> << '\n'; // outputs "true"
    
    // another way to test
    std::vector<int> v = {0,1,2};
    std::cout << std::boolalpha << std::contiguous_iterator<decltype(v)::iterator>; // outputs true
}

forward_iterator

Rendelkezik egy és egy input_iteratoroutput_iterator. Támogatja a gyűjtemények többszöri iterálását.

template<class I>
    concept forward_iterator =
        input_iterator<I> &&
        derived_from<ITER_CONCEPT(I), forward_iterator_tag> &&
        incrementable<I> &&
        sentinel_for<I, I>;

Paraméterek

I
Az iterátor, amely ellenőrzi, hogy ez egy forward_iterator.

Megjegyzések

A forward_iterator csak előre tud lépni.

Néhány példa a tárolókra, amelyek felhasználhatók a következőkkelforward_iterator: , vector, list, unordered_set, unordered_multisetés unordered_map.unordered_multimap

Példa: forward_iterator

Az alábbi példa a forward_iterator koncepciót használja annak bemutatására, hogy az egyik vector<int> rendelkezik a következővel forward_iterator:

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

int main()
{
    // Show that vector has a forward_iterator
    std::cout << std::boolalpha << std::forward_iterator<std::vector<int>::iterator> << '\n'; // outputs "true"

    // another way to test
    std::vector<int> v = {0,1,2};
    std::cout << std::boolalpha << std::forward_iterator<decltype(v)::iterator>; // outputs true
}

input_iterator

Egy input_iterator olyan iterátor, amelyből legalább egyszer olvashat.

template<class I>
concept input_iterator =
    input_or_output_iterator<I> &&
    indirectly_readable<I> &&
    requires { typename ITER_CONCEPT(I); } &&
    derived_from<ITER_CONCEPT(I), input_iterator_tag>;

Paraméterek

I
A tesztelendő típus, amely ellenőrzi, hogy ez egy input_iterator.

Megjegyzések

begin() A többszöri hívás input_iterator nem definiált viselkedést eredményez. Olyan típus, amely csak a modelleket input_iterator nem több-pass. Fontolja meg például a standard bemenetből (cin) való olvasást. Ebben az esetben csak egyszer olvashatja el az aktuális elemet, és nem olvashatja újra a már beolvasott karaktereket. Csak input_iterator előre olvasható, nem visszafelé.

Példa: input_iterator

Az alábbi példa a input_iterator koncepciót használja annak bemutatására, hogy a következő istream_iterator van input_iterator:

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

int main()
{
    // Show that a istream_iterator has an input_iterator
    std::cout << std::boolalpha << std::input_iterator<std::istream_iterator<int>>; // outputs true
}

input_or_output_iterator

Az an input_or_output_iterator az iterátorfogalmi osztályozás alapja. Támogatja az iterátor elhalasztását és növelését. Minden iterátormodell input_or_output_iterator.

template<class I>
concept input_or_output_iterator =
    requires(I i) {
        { *i } -> can-reference;
    } &&
    weakly_incrementable<I>;

Paraméterek

I
A tesztelendő típus, amely ellenőrzi, hogy ez egy input_or_output_iterator.

Megjegyzések

A fogalom can-reference azt jelenti, hogy a típus I hivatkozás, mutató vagy olyan típus, amely implicit módon átalakítható hivatkozássá.

Példa: input_or_output_iterator

Az alábbi példa a koncepciót használja annak megjelenítésére, hogy rendelkezik:/

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

int main()
{
    // Show that a vector has an input_or_output_iterator
    std::cout << std::boolalpha << std::input_or_output_iterator<std::vector<int>::iterator> << '\n'; // outputs true

    // another way to test
    std::vector<int> v = {0,1,2};
    std::cout << std::boolalpha << std::input_or_output_iterator<decltype(v)::iterator>; // outputs true
}

output_iterator

Az an output_iterator egy iterátor, amelybe írhat.

template<class I, class T>
concept output_iterator =
    input_or_output_iterator<I> &&
    indirectly_writable<I, T> &&
    requires(I i, T&& t) {
        *i++ = std::forward<T>(t);
    };

Paraméterek

I
A tesztelendő típus, amely ellenőrzi, hogy ez egy output_iterator.

T
Az írandó értékek típusa.

Megjegyzések

Az an output_iterator egybeesés. Vagyis csak egyszer tud írni ugyanarra az elemre.

Példa: output_iterator

Az alábbi példa a koncepciót használja annak megjelenítésére, hogy rendelkezik:/

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

int main()
{
    // Show that vector<int> has an output_iterator
    std::cout << std::boolalpha << std::output_iterator<std::vector<int>::iterator, int> << "\n"; // outputs "true"

    // another way to test
    std::vector<int> v = {0,1,2,3,4,5};
    std::cout << std::boolalpha << std::output_iterator<decltype(v)::iterator, int>; // outputs true
}

random_access_iterator

Egy random_access_iterator írási vagy olvasási lehetőség index alapján.

template<class I>
concept random_access_iterator =
    bidirectional_iterator<I> &&
    derived_from<ITER_CONCEPT(I), random_access_iterator_tag> &&
    totally_ordered<I> &&
    sized_sentinel_for<I, I> &&
    requires(I i, const I j, const iter_difference_t<I> n) {
        { i += n } -> same_as<I&>;
        { j + n } -> same_as<I>;
        { n + j } -> same_as<I>;
        { i -= n } -> same_as<I&>;
        { j - n } -> same_as<I>;
        { j[n] } -> same_as<iter_reference_t<I>>;
    };

Paraméterek

I
A tesztelni kívánt típus, amely ellenőrzi, hogy ez egy random_access_iterator.

Megjegyzések

Az A random_access_iterator rendelkezik a input_iterator, output_iterator, forward_iteratorés bidirectional_iterator.

Néhány példa a következőkre random_access_iterator : vector, arrayés deque.

Példa: random_access_iterator

Az alábbi példa azt mutatja be, hogy a következő vector<int>random_access_iteratorvan:

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

int main()
{
    // Show that vector<int> has a random_access_iterator
    std::cout << std::boolalpha << std::random_access_iterator<std::vector<int>::iterator> << '\n'; // outputs "true"

    // another way to test
    std::vector<int> v = {0,1,2};
    std::cout << std::boolalpha << std::random_access_iterator<decltype(v)::iterator>; // outputs true
}    

sentinel_for

Azt adja meg, hogy egy típus egy iterátor sentinelje.

template<class S, class I>
concept sentinel_for =
    semiregular<S> &&
    input_or_output_iterator<I> &&
    weakly-equality-comparable-with <S, I>;

Paraméterek

I
Az iterátor típusa.

S
A tesztelni kívánt típus, amely ellenőrzi, hogy az egy sentinel a következőhöz I: .

Megjegyzések

A sentinel egy olyan típus, amely összehasonlítható egy iterátorsal annak megállapításához, hogy az iterátor elérte-e a végét. Ez a fogalom határozza meg, hogy a típus egy sentinel-e az egyik típushoz, amely magában foglalja a input_or_output_iterator , input_iterator, output_iterator, forward_iterator, bidirectional_iteratorés random_access_iterator.contiguous_iterator

Példa: sentinel_for

Az alábbi példa a koncepciót használja annak sentinel_for megjelenítésére, hogy vector<int>::iterator az egy sentinel a következőhöz vector<int>:

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

int main()
{
    std::vector<int> v = {0, 1, 2};
    std::vector<int>::iterator i = v.begin();
    // show that vector<int>::iterator is a sentinel for vector<int>
    std::cout << std::boolalpha << std::sentinel_for<std::vector<int>::iterator, decltype(i)>; // outputs true
}    

sized_sentinel_for

Ellenőrizze, hogy egy iterátor és annak sentinelje kivonható-e - a különbség állandó időben történő megkereséséhez.

template<class S, class I>
concept sized_sentinel_for =
    sentinel_for<S, I> &&
    !disable_sized_sentinel_for<remove_cv_t<S>, remove_cv_t<I>> &&
    requires(const I& i, const S& s) {
        {s - i} -> same_as<iter_difference_t<I>>;
        {i - s} -> same_as<iter_difference_t<I>>;
    };

Paraméterek

I
Az iterátor típusa.

S
A tesztelendő sentinel típusa.

Példa: sized_sentinel_for

Az alábbi példa a sized_sentinel_for koncepciót használja annak ellenőrzésére vector<int> , hogy egy adott sentinelje kivonható-e a vektorok iterátorából állandó időben:

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

int main()
{
    std::vector<int> v = { 1, 2, 3 };
    std::vector<int>::iterator i = v.begin();
    std::vector<int>::iterator end = v.end();
    // use the sized_sentinel_for concept to verify that i can be subtracted from end in constant time
    std::cout << std::boolalpha << std::sized_sentinel_for<decltype(end), decltype(i)> << "\n"; // outputs true
    std::cout << end - i; // outputs 3
}    

Lásd még

Tartományfogalmak
Távolsági adapterek
Osztályok megtekintése