std::ranges::clamp
| Definiert in Header <algorithm> |
||
| Aufruf-Signatur |
||
| template< class T, class Proj = std::identity, std::indirect_strict_weak_order<std::projected<const T*, Proj>> Comp = |
(seit C++20) | |
Wenn der Wert von v innerhalb von [lo, hi] liegt, wird v zurückgegeben; andernfalls wird die nächstgelegene Grenze zurückgegeben.
Das Verhalten ist undefiniert, wenn lo größer als hi ist.
Die auf dieser Seite beschriebenen funktionsähnlichen Entitäten sind Algorithmus-Funktionsobjekte (informell als niebloids bekannt), d.h.
- Können explizite Template-Argumentlisten bei keinem von ihnen angegeben werden.
- Keiner von ihnen ist für Argument-abhängige Suche sichtbar.
- Wenn einer von ihnen durch normale unqualifizierte Suche als Name links vom Funktionsaufrufoperator gefunden wird, wird die Argument-abhängige Suche unterdrückt.
Inhalt |
[bearbeiten] Parameter
| v | - | Der Wert, der geklemmt werden soll |
| lo, hi | - | die Grenzen, auf die v geklemmt werden soll |
| comp | - | Der Vergleich, der auf die projizierten Elemente angewendet werden soll |
| proj | - | Die Projektion, die auf v, lo und hi angewendet werden soll |
[bearbeiten] Rückgabewert
Referenz auf lo, wenn der projizierte Wert von v kleiner ist als der projizierte Wert von lo, Referenz auf hi, wenn der projizierte Wert von hi kleiner ist als der projizierte Wert von v, andernfalls Referenz auf v.
[bearbeiten] Komplexität
Höchstens zwei Vergleiche und drei Anwendungen der Projektion.
[bearbeiten] Mögliche Implementierung
struct clamp_fn { template<class T, class Proj = std::identity, std::indirect_strict_weak_order<std::projected<const T*, Proj>> Comp = std::ranges::less> constexpr const T& operator()(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {}) const { auto&& pv = std::invoke(proj, v); if (std::invoke(comp, std::forward<decltype(pv)>(pv), std::invoke(proj, lo))) return lo; if (std::invoke(comp, std::invoke(proj, hi), std::forward<decltype(pv)>(pv))) return hi; return v; } }; inline constexpr clamp_fn clamp; |
[bearbeiten] Hinweise
std::ranges::clamp per Referenz erzeugt eine verwaiste Referenz, wenn einer der Parameter ein temporäres Objekt ist und dieser Parameter zurückgegeben wird.int n = -1; const int& r = std::ranges::clamp(n, 0, 255); // r is dangling
Wenn v mit einer der Grenzen als äquivalent verglichen wird, wird eine Referenz auf v zurückgegeben, nicht auf die Grenze.
Diese Funktion sollte nicht mit einer Projektion verwendet werden, die per Wert zurückgibt, und einem Komparator, der Argumente per Wert annimmt, es sei denn, ein Verschieben vom Rückgabetyp des Projektionsergebnisses zum Parametertyp des Komparators ist äquivalent zu einer Kopie. Wenn der Vergleich über std::invoke das Ergebnis der Projektion ändern würde, ist das Verhalten aufgrund der semantischen Anforderungen von std::regular_invocable (enthalten in std::indirect_strict_weak_order) undefiniert.
Der Standard verlangt, dass die Wertkategorie des Ergebnisses der Projektion beibehalten wird, und proj kann nur einmal für v aufgerufen werden, was bedeutet, dass ein Projektionsergebnis, das ein prvalue ist, zwischengespeichert und zweimal verschoben werden muss, um die beiden Aufrufe des Komparators durchzuführen.
- libstdc++ hält sich nicht daran und übergibt das Projektionsergebnis immer als lvalue.
- libc++ führte die Projektion zweimal aus, was in Clang 18 behoben wurde.
- MSVC STL führte die Projektion zweimal aus, was in VS 2022 17.2 behoben wurde.
[bearbeiten] Beispiel
#include <algorithm> #include <cstdint> #include <iomanip> #include <iostream> #include <string> using namespace std::literals; namespace ranges = std::ranges; int main() { std::cout << "[raw] [" << INT8_MIN << ',' << INT8_MAX << "] " "[0" << ',' << UINT8_MAX << "]\n"; for (int const v : {-129, -128, -1, 0, 42, 127, 128, 255, 256}) std::cout << std::setw(4) << v << std::setw(11) << ranges::clamp(v, INT8_MIN, INT8_MAX) << std::setw(8) << ranges::clamp(v, 0, UINT8_MAX) << '\n'; std::cout << std::string(23, '-') << '\n'; // Projection function const auto stoi = [](std::string s) { return std::stoi(s); }; // Same as above, but with strings for (std::string const v : {"-129", "-128", "-1", "0", "42", "127", "128", "255", "256"}) std::cout << std::setw(4) << v << std::setw(11) << ranges::clamp(v, "-128"s, "127"s, {}, stoi) << std::setw(8) << ranges::clamp(v, "0"s, "255"s, {}, stoi) << '\n'; }
Ausgabe
[raw] [-128,127] [0,255] -129 -128 0 -128 -128 0 -1 -1 0 0 0 0 42 42 42 127 127 127 128 127 128 255 127 255 256 127 255 ----------------------- -129 -128 0 -128 -128 0 -1 -1 0 0 0 0 42 42 42 127 127 127 128 127 128 255 127 255 256 127 255
[bearbeiten] Siehe auch
| (C++20) |
Gibt den kleineren der beiden Werte zurück (Algorithmus-Funktionsobjekt) |
| (C++20) |
Gibt den größeren der beiden Werte zurück (Algorithmus-Funktionsobjekt) |
| (C++20) |
prüft, ob ein Ganzzahlwert im Bereich eines gegebenen Ganzzahltyps liegt (Funktionsvorlage) |
| (C++17) |
klemmt einen Wert zwischen einem Paar von Grenzwerte (Funktionsvorlage) |