std::ranges::shift_left, std::ranges::shift_right
| Definiert in Header <algorithm>
|
||
| Aufrufsignatur |
||
template< std::permutable I, std::sentinel_for<I> S >
constexpr ranges::subrange<I>
shift_left( I first, S last, std::iter_difference_t<I> n );
|
(1) | (seit C++23) |
template< ranges::forward_range R >
requires std::permutable<ranges::iterator_t<R>>
constexpr ranges::borrowed_subrange_t<R>
shift_left( R&& r, ranges::range_difference_t<R> n );
|
(2) | (seit C++23) |
template< std::permutable I, std::sentinel_for<I> S >
constexpr ranges::subrange<I>
shift_right( I first, S last, std::iter_difference_t<I> n );
|
(3) | (seit C++23) |
template< ranges::forward_range R >
requires std::permutable<ranges::iterator_t<R>>
constexpr ranges::borrowed_subrange_t<R>
shift_right( R&& r, ranges::range_difference_t<R> n );
|
(4) | (seit C++23) |
Verschiebt die Elemente im Bereich [first, last) oder r um n Positionen. Das Verhalten ist undefiniert, wenn [first, last) kein gültiger Bereich ist.
- Wenn
n == 0 || n >= last - first, hat das keine Auswirkungen. - Wenn
n < 0, ist das Verhalten undefiniert. - Andernfalls wird für jede ganze Zahl
iin[0,last - first - n)das Element, das sich ursprünglich an Positionfirst + n + ibefindet, an Positionfirst + iverschoben. Die Verschiebungen werden in aufsteigender Reihenfolge vonibeginnend bei0durchgeführt.
- Wenn
n == 0 || n >= last - first, hat das keine Auswirkungen. - Wenn
n < 0, ist das Verhalten undefiniert. - Andernfalls wird für jede ganze Zahl
iin[0,last - first - n)das Element, das sich ursprünglich an Positionfirst + ibefindet, an Positionfirst + n + iverschoben. WennIdas Modell bidirectional_iterator erfüllt, werden die Verschiebungen in absteigender Reihenfolge vonibeginnend beilast - first - n - 1durchgeführt.
r als Bereich, als ob ranges::begin(r) als first und ranges::end(r) als last verwendet würden.Elemente, die sich im ursprünglichen Bereich befinden, aber nicht im neuen Bereich, werden in einem gültigen, aber unspezifizierten Zustand belassen.
Die auf dieser Seite beschriebenen funktionsähnlichen Entitäten sind Algorithmus-Funktionsobjekte (informell als Niebloids bekannt), das heißt:
- Explizite Vorlagenargumentlisten können beim Aufruf keiner von ihnen angegeben werden.
- Keine von ihnen ist für argumentabhängige Suche sichtbar.
- Wenn eine von ihnen durch normale unqualifizierte Suche als Name links vom Funktionsaufrufoperator gefunden wird, wird argumentabhängige Suche unterbunden.
Parameter
| first, last | - | das Iterator-Sentinel-Paar, das den Bereich der zu verschiebenden Elemente definiert |
| r | - | der Bereich der zu verschiebenden Elemente |
| n | - | die Anzahl der zu verschiebenden Positionen |
Rückgabewert
NEW_LAST
das Ende des resultierenden Bereichs ist und äquivalent zu:
-
first
+
(
last
-
first
-
n
)
, falls
nkleiner ist als last - first ; - first andernfalls.
NEW_FIRST
der Anfang des resultierenden Bereichs ist und äquivalent zu:
-
first
+
n
, falls
nkleiner als last - first ist; - last andernfalls.
Komplexität
Hinweise
ranges::shift_left
/
ranges::shift_right
haben auf gängigen Implementierungen eine bessere Effizienz, wenn
I
das Konzept
bidirectional_iterator
oder (noch besser)
random_access_iterator
modelliert.
Implementierungen (z.B.
MSVC STL
) können Vektorisierung ermöglichen, wenn der Iteratortyp
contiguous_iterator
modelliert und das Vertauschen seines Werttyps weder nicht-triviale spezielle Memberfunktionen noch
ADL
-gefundene
swap
-Funktionen aufruft.
| Feature-Test-Makro | Wert | Std | Feature |
|---|---|---|---|
__cpp_lib_shift
|
202202L
|
(C++23) |
std::ranges::shift_left
und
std::ranges::shift_right
|
Beispiel
#include <algorithm> #include <iostream> #include <string> #include <type_traits> #include <vector> struct S { int value{0}; bool specified_state{true}; S(int v = 0) : value{v} {} S(S const& rhs) = default; S(S&& rhs) { *this = std::move(rhs); } S& operator=(S const& rhs) = default; S& operator=(S&& rhs) { if (this != &rhs) { value = rhs.value; specified_state = rhs.specified_state; rhs.specified_state = false; } return *this; } }; template<typename T> std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) { for (const auto& s : v) { if constexpr (std::is_same_v<T, S>) s.specified_state ? os << s.value << ' ' : os << ". "; else if constexpr (std::is_same_v<T, std::string>) os << (s.empty() ? "." : s) << ' '; else os << s << ' '; } return os; } int main() { std::cout << std::left; std::vector<S> a{1, 2, 3, 4, 5, 6, 7}; std::vector<int> b{1, 2, 3, 4, 5, 6, 7}; std::vector<std::string> c{"α", "β", "γ", "δ", "ε", "ζ", "η"}; std::cout << "vector<S> \tvector<int> \tvector<string>\n"; std::cout << a << " " << b << " " << c << '\n'; std::ranges::shift_left(a, 3); std::ranges::shift_left(b, 3); std::ranges::shift_left(c, 3); std::cout << a << " " << b << " " << c << '\n'; std::ranges::shift_right(a, 2); std::ranges::shift_right(b, 2); std::ranges::shift_right(c, 2); std::cout << a << " " << b << " " << c << '\n'; std::ranges::shift_left(a, 8); // hat keine Wirkung: n >= last - first std::ranges::shift_left(b, 8); // ditto std::ranges::shift_left(c, 8); // ditto std::cout << a << " " << b << " " << c << '\n'; // std::ranges::shift_left(a, -3); // UB }
Mögliche Ausgabe:
vector<S> vector<int> vector<string> 1 2 3 4 5 6 7 1 2 3 4 5 6 7 α β γ δ ε ζ η 4 5 6 7 . . . 4 5 6 7 5 6 7 δ ε ζ η . . . . . 4 5 6 7 . 4 5 4 5 6 7 5 . . δ ε ζ η . . . 4 5 6 7 . 4 5 4 5 6 7 5 . . δ ε ζ η .
Siehe auch
(C++20) |
verschiebt einen Bereich von Elementen an einen neuen Ort (Algorithmus-Funktionsobjekt) |
(C++20) |
verschiebt einen Bereich von Elementen in umgekehrter Reihenfolge an einen neuen Ort (Algorithmus-Funktionsobjekt) |
(C++20) |
dreht die Reihenfolge der Elemente in einem Bereich (Algorithmus-Funktionsobjekt) |
(C++20)(C++20) |
verschiebt Elemente in einem Bereich (Funktionsvorlage) |