<ranges>
-Aliasvorlagen
Eine Aliasvorlage ist ein Alias für einen anderen Typ, wodurch Code besser lesbar sein kann. Der folgende Alias ist conditional_t
beispielsweise ein Alias für einen borrowed_range
oder dangling
einen Bereich, abhängig von der Art der range
Übergebenen:
// requires /std:c++20, or later
#include <iostream>
#include <list>
#include <span>
#include <algorithm>
#include <ranges>
#include <type_traits>
using namespace std;
// Define an alias template called my_iterator_t
// If the provided range R is a borrowed_range, then the
// returned type is iterator_t<R>; otherwise, ranges::dangling
template<ranges::range R>
using my_iterator_t = conditional_t<
ranges::borrowed_range<R>,
ranges::iterator_t<R>, ranges::dangling>;
int main()
{
my_iterator_t<list<int>> aDanglingRange; // list<> isn't a borrowed_range
constexpr bool same = same_as<
decltype(aDanglingRange),
ranges::dangling>; // true
my_iterator_t<span<int, 5>> anIterator_t; // span<> is a borrowed_range
constexpr bool same2 = same_as<
decltype(anIterator_t),
ranges::iterator_t<span<int, 5>>>; // true
cout << boolalpha << same << "," << same2; // outputs true, true
}
Weitere Informationen zu Aliasvorlagen finden Sie unter Aliase und Typedefs.
Die <algorithm>
Kopfzeile definiert die folgenden Aliasvorlagen, die die Typen von Iteratoren und Sentinels für ein range
:
Aliasvorlage | Beschreibung |
---|---|
borrowed_iterator_t C++20 |
Ermitteln Sie, ob ein für einen range Bereich zurückgegebener Iterator auf einen Bereich verweist, dessen Lebensdauer beendet wurde. |
borrowed_subrange_t C++20 |
Ermitteln Sie, ob ein subrange zurückgegebener Wert auf einen range Bereich verweist, dessen Lebensdauer beendet wurde. |
dangling C++20 |
Gibt an, dass der zurückgegebene Iterator eines range /subrange Iterators die Lebensdauer des range /subrange Iterators überlebt. |
iterator_t C++20 |
Gibt den Iteratortyp für den angegebenen Bereich zurück. |
range_difference_t C++20 |
Gibt den Differenztyp für den Iterator des angegebenen Bereichs zurück. |
range_reference_t C++20 |
Gibt den Bezugstyp für den Iterator des angegebenen Bereichs zurück. |
range_rvalue_reference_t C++20 |
Gibt den Rvalue-Bezugstyp für den Iterator des angegebenen Bereichs zurück. Mit anderen Worten, der Rvalue-Bezugstyp der Elemente des Bereichs. |
range_size_t C++20 |
Gibt den Typ zurück, der zum Melden des angegebenen Bereichs size verwendet wird. |
range_value_t C++20 |
Gibt den Werttyp des angegebenen Bereichs iterator zurück. Oder mit anderen Worten, der Typ der Elemente im Bereich. |
sentinel_t C++20 |
Gibt den Sentineltyp für den angegebenen Bereich zurück. |
borrowed_iterator_t
Wenn eine Algorithmusfunktion, die einen Iterator zurückgibt, mit einem Rvalue-Argument range
aufgerufen wird, kann die Lebensdauer des Bereichs nach dem Aufruf enden. Das bedeutet, dass der zurückgegebene Iterator auf Elemente verweisen kann, deren Lebensdauer beendet wurde. Die Verwendung eines nicht definierten Iterators führt zu einem nicht definierten Verhalten.
Dieser Vorlagenalias gibt zurück ranges::dangling
, um anzugeben, dass dies die Situation für das angegebene Bereichsargument ist, oder std::ranges::iterator_t<R>
um anzugeben, dass es sicher ist, den zurückgegebenen Iterator zu verwenden, da der Bereich, der auf Modelle borrowed_range
verweist, oder der Bereich als lvalue übergeben wurde.
template<ranges::range R>
using borrowed_iterator_t = conditional_t<ranges::borrowed_range<R>,
ranges::iterator_t<R>, ranges::dangling>;
Parameter
R
Der zu testende Bereich.
Hinweise
Die Lebensdauer eines Wertebereichs kann nach einem Funktionsaufruf enden, unabhängig davon, ob die Bereichsmodelle vorliegen borrowed_range
oder nicht. Wenn es sich um eins borrowed_range
handelt, können Sie die Iteratoren möglicherweise weiterhin mit einem gut definierten Verhalten verwenden, unabhängig davon, wann die Lebensdauer des Bereichs endet.
Fälle, in denen dies nicht zutrifft, z. B. für Container wie vector
oder list
weil die Lebensdauer des Containers endet, beziehen sich die Iteratoren auf Elemente, die zerstört wurden.
Sie können weiterhin die Iteratoren für ein borrowed_range
, z. B. für ein view
Ähnliches iota_view<int>{0, 42}
verwenden, dessen Iteratoren über Sätze von Werten liegen, die nicht zerstört werden müssen, weil sie bei Bedarf generiert werden.
Wenn eine Algorithmusfunktion einen Bereich übergeben wird, dessen Iteratoren von ihrer Lebensdauer abhängen, ranges::dangling
wird anstelle eines Iterators oder Unterbereichs zurückgegeben, sodass potenzieller Missbrauch zur Kompilierungszeit erkannt wird.
Beispiel: borrowed_iterator_t
Im folgenden Beispiel wird gezeigt, wie borrowed_iterator_t
ein geschwängeriger Iterator erkannt wird. Die Funktion ranges::max_element()
verwendet diesen Vorlagenalias, um den Rückgabetyp zu bestimmen:
// requires /std:c++20, or later
#include <vector>
#include <span>
#include <ranges>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
// Not dangling ------------------
int a[] = {0,1,2,3};
// not dangling even though an rvalue because span models ranges::borrowed
auto result1 = ranges::max_element(span{a});
cout << boolalpha << ranges::borrowed_range<decltype(span{a})> << endl; // outputs true because the temporary models ranges::borrowed
cout << same_as<decltype(result1), ranges::dangling> << endl; // outputs false because the result isn't dangling
vector<int> v{0,1,2,3}; // doesn't model ranges::borrowed
auto result2 = ranges::max_element(v); // Yet not dangling because passed as an lvalue
cout << same_as<decltype(result2), ranges::dangling> << endl; // outputs false because the result isn't dangling
// Dangling ------------------
auto result3 = ranges::max_element(vector{0,1,2,3}); // dangling because vector doesn't model ranges::borrowed and is passed as an rvalue
cout << same_as<decltype(result3), ranges::dangling>; // outputs true because the result is dangling
}
true
false
false
true
borrowed_subrange_t
Wenn eine Algorithmusfunktion, die eine subrange
zurückgibt, mit einem Rvalue-Argument range
aufgerufen wird, kann die Lebensdauer des Bereichs nach dem Aufruf enden. Dies bedeutet, dass die zurückgegebenen subrange
Elemente auf Elemente verweisen können, deren Lebensdauer beendet wurde. Die Verwendung eines Danglings subrange
führt zu einem nicht definierten Verhalten.
Dieser Vorlagenalias gibt ranges::dangling
entweder zurück, um anzugeben, dass dies die Situation für das angegebene Bereichsargument sein könnte, oder subrange<ranges::iterator_t<R>>
um anzugeben, dass es sicher ist, den zurückgegebenen Unterbereich zu verwenden, da entweder der Bereich, dessen Elemente es auf Modelle borrowed_range
verweist, oder der Bereich als lvalue übergeben wurde.
template<ranges::range R>
using borrowed_subrange_t = conditional_t<ranges::borrowed_range<R>,
ranges::subrange<ranges::iterator_t<R>>, ranges::dangling>;
Parameter
R
Der zu testende Bereich.
Hinweise
Die Lebensdauer eines Wertebereichs kann nach einem Funktionsaufruf enden, unabhängig davon, ob die Bereichsmodelle vorliegen borrowed_range
oder nicht. Wenn es sich um eins borrowed_range
handelt, können Sie die Iteratoren möglicherweise weiterhin mit einem gut definierten Verhalten verwenden, unabhängig davon, wann die Lebensdauer des Bereichs endet.
Fälle, in denen dies nicht zutrifft, z. B. für Container wie vector
oder list
weil die Lebensdauer des Containers endet, beziehen sich die Iteratoren auf Elemente, die zerstört wurden.
Sie können weiterhin die Iteratoren für ein borrowed_range
, z. B. für ein view
Ähnliches iota_view<int>{0, 42}
verwenden, dessen Iteratoren über Sätze von Werten liegen, die nicht zerstört werden müssen, weil sie bei Bedarf generiert werden.
Wenn eine Algorithmusfunktion an einen Bereich übergeben wird, dessen Iteratoren von ihrer Lebensdauer abhängen, wird anstelle eines Unterbereichs zurückgegeben, ranges::dangling
sodass potenzieller Missbrauch zur Kompilierungszeit erkannt wird.
Beispiel: borrowed_subrange_t
Im folgenden Beispiel wird gezeigt, wie borrowed_subrange_t
ein verdrückendes Iterator erkannt wird, da equal_range()
dieser max_element
Vorlagenalias verwendet wird, um den Rückgabetyp zu bestimmen:
// requires /std:c++20, or later
#include <vector>
#include <iostream>
#include <algorithm>
#include <span>
#include <ranges>
int main()
{
using namespace std;
// Not dangling ------------------
vector vec{0, 1, 1, 2};
auto result1 = ranges::equal_range(span{vec}, 1); // not dangling even though passing as an rvalue because span models borrowed_range
cout << boolalpha << ranges::borrowed_range<decltype(span{vec})> << endl; // true because the temporary is a borrowed range
cout << boolalpha << same_as<decltype(result1), ranges::dangling> << endl; // false because the result isn't dangling
// result2 isn't dangling even though vec doesn't model ranges::borrowed because it's an lvalue
auto result2 = ranges::max_element(vec);
cout << boolalpha << ranges::borrowed_range<decltype(vec)> << endl; // false because vector isn't a borrowed_range
cout << boolalpha << same_as<decltype(result2), ranges::dangling> << endl; // false because the result isn't dangling
// Dangling -----------------------
// result3 is dangling because the temporary is an rvalue that doesn't model borrowed_range
auto result3 = ranges::max_element(vector{0,1,1,2});
cout << boolalpha << same_as<decltype(result3), ranges::dangling> << endl; // true because the result is dangling
}
true
false
false
false
true
dangling
Wenn eine Algorithmusfunktion, die einen Iterator zurückgibt oder ein subrange
Argument mit einem Wert range
aufgerufen wird, kann die Lebensdauer des Bereichsarguments nach dem Aufruf enden. Das bedeutet, dass der zurückgegebene Iterator auf subrange
Elemente verweisen kann, deren Lebensdauer beendet wurde. Die Verwendung eines nicht definierten Iterators oder subrange
führt zu einem nicht definierten Verhalten.
Wenn eine Algorithmusfunktion an einen Bereich übergeben wird, dessen Iteratoren von ihrer Lebensdauer abhängig sind, wird anstelle eines Iterators oder Unterbereichs zurückgegeben, ranges::dangling
sodass potenzieller Missbrauch zur Kompilierungszeit erkannt wird.
1) constexpr dangling() noexcept = default;
2) template<class... Args>
constexpr dangling(Args&&...) noexcept {}
Parameter
Args
Eine variable Anzahl von Nichttypenvoid
. Sie haben keine Wirkung. Die Argumente sind eine Benutzerfreundlichkeit, sodass Sie keine anderen Codepfade benötigen, um das Erstellen des Iteratortyps dangling
im Vergleich zum Typ zu behandeln. Dies ist nützlich, wenn der übergebene Wert angibt, dass dangling
anstelle eines Iterators zurückgegeben werden soll.
Beispiel: dangling
Im folgenden Beispiel wird gezeigt, wie max_element
ein geschwängeriger Iterator erkannt wird.
// requires /std:c++20, or later
#include <vector>
#include <iostream>
#include <ranges>
#include <algorithm>
using namespace std;
int main()
{
auto result1 = ranges::max_element(vector{1,2,3}); // dangling because vector doesn't model ranges::borrowed and is passed as an rvalue
cout << boolalpha << same_as<decltype(result1), ranges::dangling> << endl; // outputs true because the result is dangling
vector<int> v{3,4,5};
auto result2 = ranges::max_element(v); // Not dangling because passed as an lvalue
cout << same_as<decltype(result2), ranges::dangling>; // outputs false because the result isn't dangling
}
true
false
iterator_t
Dieser Vorlagenalias gibt den Iteratortyp zurück, der zum Durchlaufen des angegebenen Bereichstyps verwendet wird.
template<class T>
using iterator_t = decltype(ranges::begin(declval<T&>()));
Parameter
T
Der Bereichstyp, für den der Iteratortyp abgerufen werden soll.
Beispiel: iterator_t
Das folgende Beispiel zeigt, wie iterator_t
sie zum Deklarieren eines Iterators für einen Vektor verwendet werden können:
// requires /std:c++20, or later
#include <vector>
#include <ranges>
#include <iostream>
int main()
{
using namespace std;
vector<int> v{1,2,3};
ranges::iterator_t<decltype(v)> it = v.begin();
cout << *it << "\n"; // outputs 1
cout << typeid(it).name(); // outputs class _Vector_iterator<class _Vector_val<struct _Simple_types<int>>>
}
1
class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<int> > >
range_difference_t
Gibt den Differenztyp für den Iterator des angegebenen Bereichs zurück.
template<range R>
using range_difference_t = iter_difference_t<iterator_t<R>>;
Parameter
R
Der Bereich, dessen Iterator den Differenztyp bereitstellt.
Beispiel: range_difference_t
Das folgende Beispiel zeigt, wie range_difference_t
der Abstand zwischen Elementen in einem Bereich gehalten wird:
// requires /std:c++20, or later
#include <vector>
#include <ranges>
#include <iostream>
int main()
{
using namespace std;
vector<int> v{1,2,3};
auto findIt = ranges::find(v, 2);
// type of distance is ptrdiff_t
ranges::range_difference_t<decltype(v)> distance = ranges::distance(v.begin(), findIt);
cout << distance << endl; // outputs 1
}
1
range_reference_t
Gibt den Bezugstyp für den Iterator des angegebenen Bereichs zurück. Mit anderen Worten, der Bezugstyp der Elemente des Bereichs.
template <range R>
using range_reference_t = iter_reference_t<ranges::iterator_t<R>>;
Parameter
R
Der Bereich, für den der Bezugstyp des Iteratortyps zurückgegeben wird.
Beispiel: range_reference_t
Das folgende Beispiel zeigt range_reference_t
den Bezug auf den Typ der Elemente in einem Bereich:
// requires /std:c++20, or later
#include <vector>
#include <ranges>
#include <iostream>
int main()
{
using namespace std;
vector<int> v{1,2,3};
ranges::range_reference_t<decltype(v)> ref = v[0];
cout << ref << endl; // outputs 1
cout << typeid(ref).name() << endl; // outputs int
}
1
int
range_rvalue_reference_t
Gibt den Rvalue-Bezugstyp für den Iterator des angegebenen Bereichs zurück. Mit anderen Worten, der Rvalue-Bezugstyp der Elemente des Bereichs.
template <range R>
using range_rvalue_reference_t = iter_reference_t<ranges::iterator_t<R>>;
Parameter
R
Der Bereich, um den Rvalue-Bezugstyp auf den Iteratortyp abzurufen.
Beispiel: range_rvalue_reference_t
Das folgende Beispiel zeigt range_rvalue_reference_t
einen Verweis auf einen Werttyp der Elemente in einem Bereich:
// requires /std:c++20, or later
#include <vector>
#include <ranges>
#include <iostream>
int main()
{
using namespace std;
vector<int> v{1,2,3};
ranges::range_rvalue_reference_t<decltype(v)> elementRvalueType = v[0] * 10; // elementRvalueType is int&&
cout << elementRvalueType << endl; // outputs 10
cout << typeid(elementRvalueType).name() << endl; // outputs int
}
10
int
range_size_t
Gibt den Typ der size
Funktion für die angegebene sized_range
.
template <range R>
using range_size_t = iter_reference_t<ranges::iterator_t<R>>;
Parameter
R
Der Bereich, der den Typ seiner size
Funktion abrufen soll.
Beispiel: range_size_t
Im folgenden Beispiel wird range_size_t
auf die Anzahl der Elemente in einem Bereich verwiesen:
// requires /std:c++20, or later
#include <vector>
#include <iostream>
#include <ranges>
int main()
{
using namespace std;
vector<int> v{1,2,3};
ranges::range_size_t<decltype(v)> size = v.size();
cout << size << endl; // outputs 3
cout << typeid(size).name(); // outputs unsigned __int64
}
3
unsigned __int64
range_value_t
Gibt den Werttyp des angegebenen Bereichs iterator zurück. Oder mit anderen Worten, der Typ der Elemente im Bereich.
template <ranges::range R>
using range_value_t = iter_value_t<ranges::iterator_t<R>>;
Parameter
R
Der Bereich, der den Werttyp des Iterators abrufen soll.
Beispiel: range_value_t
Das folgende Beispiel zeigt, wie range_value_t
sich auf den Typ der Elemente in einem Bereich bezieht:
// requires /std:c++20, or later
#include <vector>
#include <ranges>
#include <iostream>
int main()
{
using namespace std;
vector<int> v{1,2,3};
ranges::range_value_t<decltype(v)> elementType = v[2]; // elementType is an int
cout << elementType << endl; // outputs 3
cout << typeid(elementType).name() << endl; // outputs int
}
3
unsigned int
sentinel_t
Gibt den Sentineltyp für den angegebenen Bereich zurück.
template <range R>
using sentinel_t = decltype(ranges::end(declval<R&>()));
Parameter
R
Der Bereich, für den der Sentineltyp abgerufen werden soll.
Beispiel: sentinel_t
Im folgenden Beispiel wird gezeigt sentinel_t
, ob der Iteratortyp und sentineltyp identisch sind:
// requires /std:c++20, or later
#include <iostream>
#include <list>
#include <ranges>
int main()
{
using namespace std;
list myList{1, 2, 3};
ranges::subrange count = std::views::counted(myList.begin(), myList.size());
ranges::iterator_t<decltype(count)> first;
ranges::sentinel_t<decltype(count)> last;
// The iterator type and the sentinel type of a subrange
// obtained from views::counted are not the same
cout << boolalpha << is_same<decltype(first), decltype(last)>::value << endl; // outputs false
cout << "iter: " << typeid(first).name() << "\n\n end: " << typeid(last).name() << endl;
}
false
iter: class std::counted_iterator<class std::_List_iterator<class std::_List_val<struct std::_List_simple_types<int> > > >
end: struct std::default_sentinel_t