Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
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 olyan típusú példányosítását, 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't 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.
A tartományfogalmak a std::ranges névtérben vannak definiálva, és deklarálva vannak a <ranges> fejlécfájlban. Ezeket a tartományadafótorok, nézetek stb. deklarációiban használják.
A tartománynak hat kategóriája van. Ezek a fogalmakban<iterator> felsorolt iterátorok kategóriáihoz kapcsolódnak. A képességek növelése érdekében a kategóriák a következők:
| A tartomány fogalma | Description |
|---|---|
output_rangeinput_range |
Olyan tartományt ad meg, amelybe írhat. Egy olyan tartományt ad meg, amelyből egyszer olvashat. |
forward_range |
Olyan tartományt ad meg, amelyet többször is elolvashat (és esetleg írhat). |
bidirectional_range |
Olyan tartományt ad meg, amely előre és hátra is olvasható és írható. |
random_access_range |
Egy index alapján olvasható és írható tartományt határoz meg. |
contiguous_range |
Olyan tartományt ad meg, amelynek elemei sorrendiek a memóriában, azonos méretűek, és mutató aritmetikai használatával érhetők el. |
Az előző táblázatban a fogalmak a képesség növelésének sorrendjében vannak felsorolva. A fogalom követelményeinek megfelelő tartomány általában megfelel az azt megelőző sorokban szereplő fogalmak követelményeinek. Például az a random_access_rangebidirectional_rangeforward_range, , input_rangeés .output_range A kivétel az input_range, amely nem írható, így nem rendelkezik a képességekkel output_range.
Egyéb tartományfogalmak a következők:
| A tartomány fogalma | Description |
|---|---|
range
C++20 |
Olyan típust ad meg, amely iterátort és sentinelt biztosít. |
borrowed_range
C++20 |
Azt határozza meg, hogy a tartomány iterátorainak élettartama nincs a tartomány élettartamához kötve. |
common_range
C++20 |
Megadja, hogy a tartomány iterátorának típusa és a tartomány sentineljének típusa megegyezik. |
Simple_View
C++20 |
Nem egy hivatalos fogalom, amelyet a standard kódtár részeként határoznak meg, hanem néhány felületen segítő fogalomként használják. |
sized_range
C++20 |
Olyan tartományt határoz meg, amely hatékonyan tudja biztosítani az elemek számát. |
view
C++20 |
Olyan típust határoz meg, amely hatékony (állandó idő) áthelyezési konstrukcióval, hozzárendeléssel és megsemmisítéssel rendelkezik. |
viewable_range
C++20 |
Olyan típust ad meg, amely vagy nézet, vagy átalakítható egy nézetté. |
bidirectional_range
Az A bidirectional_range támogatja a tartomány előre és hátra olvasását és írását.
template<class T>
concept bidirectional_range =
forward_range<T> && bidirectional_iterator<iterator_t<T>>;
Paraméterek
T
A tesztelni kívánt típus, amely ellenőrzi, hogy ez egy bidirectional_range.
Megjegyzések
Ez a fajta tartomány támogatja bidirectional_iterator vagy nagyobb.
Az A bidirectional_iterator rendelkezik a képességekkel forward_iterator, de visszafelé is képes iterálni.
Néhány példa a következőkre bidirectional_range : std::set, std::vectorés std::list.
borrowed_range
Típusmodellek borrowed_range , ha az objektumból kapott iterátorok érvényessége túllépi az objektum élettartamát. Vagyis egy tartomány iterátorai akkor is használhatók, ha a tartomány már nem létezik.
template<class T>
concept borrowed_range =
range<T> &&
(is_lvalue_reference_v<T> || enable_borrowed_range<remove_cvref_t<T>>);
Paraméterek
T
A tesztelni kívánt típus, amely ellenőrzi, hogy ez egy borrowed_range.
Megjegyzések
Az rvalue-tartomány élettartama egy függvényhívás után megszűnhet, függetlenül attól, hogy a tartománymodellek borrowed_range vagy sem. Ha ez egy borrowed_range, akkor továbbra is használhatja az iterátorokat jól definiált viselkedéssel, függetlenül attól, hogy mikor ér véget a tartomány élettartama.
Azokban az esetekben, amikor ez nem igaz, például tárolók vectorlist esetében, például azért, mert a tároló élettartama véget ér, az iterátorok olyan elemekre hivatkoznak, amelyek megsemmisültek.
Továbbra is használhatja az iterátorokat például olyan view hasonlókhozborrowed_rangeiota_view<int>{0, 42}, amelyek iterátorai olyan értékeken alapulnak, amelyek nem lesznek megsemmisítve, mert igény szerint jönnek létre.
common_range
Az egyhez common_range tartozó iterátor típusa megegyezik a sentinel típusával. Vagyis begin()end() ugyanazt a típust adja vissza.
template<class T>
concept common_range =
ranges::range<T> && std::same_as<ranges::iterator_t<T>, ranges::sentinel_t<T>>;
Paraméterek
T
A tesztelni kívánt típus, amely ellenőrzi, hogy ez egy common_range.
Megjegyzések
A típus std::ranges::begin()std::ranges::end() lekérése olyan algoritmusok esetében fontos, amelyek kiszámítják a két iterátor közötti távolságot, valamint az iterátorpárok által megjelölt tartományokat elfogadó algoritmusok esetében.
A standard tárolók (például vector) megfelelnek a következő követelményeknek common_range: .
contiguous_range
A rendszer az elemeket contiguous_range egymás után tárolja a memóriában, és a mutató aritmetikai használatával érhető el. A tömb például egy contiguous_range.
template<class T>
concept contiguous_range =
random_access_range<T> && contiguous_iterator<iterator_t<T>> &&
requires(T& t) {{ ranges::data(t) } -> same_as<add_pointer_t<range_reference_t<T>>>;};
Paraméterek
T
A tesztelni kívánt típus, amely ellenőrzi, hogy ez egy contiguous_range.
Megjegyzések
A contiguous_range 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. Ez a fajta tartomány támogatja contiguous_iteratoraz iterátorok közül a legrugalmasabbat.
Néhány példa a következőkre contiguous_range : std::array, std::vectorés std::string.
Példa: contiguous_range
Az alábbi példa a mutató aritmetikai használatával mutatja be a következőhöz való hozzáférést contiguous_range:
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>
int main()
{
// Show that vector is a contiguous_range
std::vector<int> v = {0,1,2,3,4,5};
std::cout << std::boolalpha << std::ranges::contiguous_range<decltype(v)> << '\n'; // outputs true
// Show that pointer arithmetic can be used to access the elements of a contiguous_range
auto ptr = v.data();
ptr += 2;
std::cout << *ptr << '\n'; // outputs 2
}
true
2
forward_range
A tartomány forward_range többszöri olvasását (és esetleg írását) támogatja.
template<class T>
concept forward_range = input_range<T> && forward_iterator<iterator_t<T>>;
Paraméterek
T
A tesztelni kívánt típus, amely ellenőrzi, hogy ez egy forward_range.
Megjegyzések
Ez a fajta tartomány támogatja forward_iterator vagy nagyobb. Egy forward_iterator tartományt többször is át lehet iterálni.
input_range
Az An input_range egy olyan tartomány, amely egyszer olvasható.
template<class T>
concept input_range = range<T> && input_iterator<iterator_t<T>>;
Paraméterek
T
A tesztelendő típus, amely ellenőrzi, hogy ez egy input_range.
Megjegyzések
Ha egy típus megfelel a következő követelményeknek input_range:
- A
ranges::begin()függvény egyinput_iterator. A többszöriinput_rangehívásbegin()nem definiált viselkedést eredményez. - Ismétlődően elhalaszthat egy
input_iteratorértéket, amely minden alkalommal ugyanazt az értéket eredményezi. Az aninput_rangenem több-pass. Az iterátor növekménye érvényteleníti a másolatokat. - Ez használható a
ranges::for_each. - Támogatja
input_iteratorvagy nagyobb.
output_range
Az An output_range egy tartomány, amelybe írhat.
template<class R, class T>
concept output_range = range<R> && output_iterator<iterator_t<R>, T>;
Paraméterek
R
A tartomány típusa.
T
A tartományba írandó adatok típusa.
Megjegyzések
Ennek az a jelentése output_iterator<iterator_t<R>, T> , hogy a típus egy olyan iterátort biztosít, amely típusértékeket T írhat egy típustartományba R. Más szóval támogatja output_iterator vagy nagyobb.
random_access_range
A random_access_range tartományokat indexek szerint lehet olvasni vagy írni.
template<class T>
concept random_access_range =
bidirectional_range<T> && random_access_iterator<iterator_t<T>>;
Paraméterek
T
A tesztelni kívánt típus, amely ellenőrzi, hogy ez egy random_access_range.
Megjegyzések
Ez a fajta tartomány támogatja random_access_iterator vagy nagyobb. Az A random_access_range rendelkezik a input_range, output_range, forward_rangeés bidirectional_range. A random_access_range rendezhető.
Néhány példa a következőkre random_access_range : std::vector, std::arrayés std::deque.
range
Meghatározza azokat a követelményeket, amelyekkel egy típusnak meg kell felelnie range. Az A range iterátort és egy sentinelt biztosít, hogy iterálhassa az elemeit.
template<class T>
concept range = requires(T& rg)
{
ranges::begin(rg);
ranges::end(rg);
};
Paraméterek
T
A tesztelni kívánt típus, amely ellenőrzi, hogy ez egy range.
Megjegyzések
Az a range követelmények a következők:
- Iterated
std::ranges::begin()használatával ésstd::ranges::end() -
ranges::begin()ésranges::end()futtassa az amortizált állandó időben, és ne módosítsa arange. Az amortizált állandó idő nem jelenti az O(1) értékeket, de az átlagos költség egy hívássorozat esetében még a legrosszabb esetben is O(n) és nem O(n^2) vagy rosszabb. -
[ranges::begin(), ranges::end())érvényes tartományt jelöl.
Simple_View
Az A Simple_View egy csak kiállítási fogalom, amelyet egyes ranges felületeken használnak. Nincs definiálva a kódtárban. A specifikációban csak bizonyos tartományadabrátorok viselkedésének leírására szolgál.
template<class V>
concept Simple_View = // exposition only
ranges::view<V> && ranges::range<const V> &&
std::same_as<std::ranges::iterator_t<V>, std::ranges::iterator_t<const V>> &&
std::same_as<std::ranges::sentinel_t<V>, std::ranges::sentinel_t<const V>>;
Paraméterek
V
A tesztelni kívánt típus, amely ellenőrzi, hogy ez egy Simple_View.
Megjegyzések
A nézet V akkor Simple_View tekinthető meg, ha az alábbiak mindegyike igaz:
-
Vegy nézet -
const Vtartomány -
const VMindkettővugyanazzal az iterátor- és sentineltípusokkal rendelkezik.
sized_range
Az A sized_range amortizált állandó időtartomány elemeinek számát adja meg.
template<class T>
concept sized_range = range<T> &&
requires(T& t) { ranges::size(t); };
Paraméterek
T
A tesztelni kívánt típus, amely ellenőrzi, hogy ez egy sized_range.
Megjegyzések
Az a sized_range követelmények, hogy hívja ranges::size meg:
- Nem módosítja a tartományt.
- Az amortizált állandó idő elemeinek számát adja vissza. Az amortizált állandó idő nem jelenti az O(1) értékeket, de az átlagos költség egy hívássorozat esetében még a legrosszabb esetben is O(n) és nem O(n^2) vagy rosszabb.
Néhány példa a sized_range következőkre: std::list és std::vector.
Példa: sized_range
Az alábbi példa azt mutatja, hogy az egyik vectorint a:sized_range
// requires /std:c++20 or later
#include <ranges>
#include <iostream>
#include <vector>
int main()
{
std::cout << std::boolalpha << std::ranges::sized_range<std::vector<int>> << '\n'; // outputs "true"
}
view
Az A view állandó időmozgatási konstrukciós, hozzárendelési és megsemmisítési műveletekkel rendelkezik – függetlenül attól, hogy hány elemből áll. A nézeteknek nem kell másolhatónak vagy hozzárendelhető példánynak lenniük, de ha igen, ezeknek a műveleteknek is állandó időben kell futniuk.
Az állandó időigény miatt hatékonyan írhat nézeteket. Ha például egy úgynevezett inputvektort int ad meg, egy függvény, amely meghatározza, hogy egy szám osztható-e hárommal, és egy szám négyzetével rendelkező függvény, az utasítás auto x = input | std::views::filter(divisible_by_three) | std::views::transform(square); hatékonyan létrehoz egy nézetet, amely a bemenetben lévő számok négyzeteit tartalmazza, amelyek hárommal oszthatóak. A nézetek összekötését | a nézetek írásának nevezzük. Ha egy típus megfelel a view koncepciónak, akkor hatékonyan összeállítható.
template<class T>
concept view = ranges::range<T> && std::movable<T> && ranges::enable_view<T>;
Paraméterek
T
A tesztelni kívánt típus, amely ellenőrzi, hogy nézet-e.
Megjegyzések
A nézet összeállításának alapvető követelménye az, hogy olcsó az áthelyezés/másolás. Ennek az az oka, hogy a nézet áthelyezése/másolása egy másik nézettel való összeállításkor történik. Mozgatható tartománynak kell lennie.
ranges::enable_view<T> a fogalom szemantikai követelményeinek való megfelelés igénylésére view használt tulajdonság. Egy típus a következő módon tud bejelentkezni:
- nyilvánosan és egyértelműen a
ranges::view_interface - nyilvánosan és egyértelműen az üres osztályból
ranges::view_baseszármazik, vagy - szakterülete
ranges::enable_view<T>:true
Az 1. lehetőség előnyben részesített, mert view_interface az alapértelmezett implementációt is biztosítja, amely ment néhány írandó sablonkódot.
Ennek hiányában a 2. lehetőség egy kicsit egyszerűbb, mint a 3. lehetőség.
A 3. lehetőség előnye, hogy a típus definíciójának módosítása nélkül is lehetséges.
viewable_range
Az A viewable_range egy nézet vagy átalakítható nézetté.
template<class T>
concept viewable_range =
range<T> && (borrowed_range<T> || view<remove_cvref_t<T>>);
Paraméterek
T
A tesztelni kívánt típus, amely ellenőrzi, hogy az nézet-e, vagy átalakítható-e egy nézetté.
Megjegyzések
Egy tartomány nézetté alakításához használható std::ranges::views::all() .