Namespaces
Variants

std::ranges::clamp

Von de.cppreference.net
 
 
Algorithmenbibliothek
Eingeschränkte Algorithmen und Algorithmen auf Bereichen (C++20)
Eingeschränkte Algorithmen, z.B. ranges::copy, ranges::sort, ...
Nicht modifizierende Sequenzoperationen    
Stapeloperationen
(C++17)
Suchoperationen
Modifizierende Sequenzoperationen
Kopieroperationen
(C++11)
(C++11)
Tauschoperationen
Transformationsoperationen
Erzeugungsoperationen
Entfernungsoperationen
Reihenfolgeändernde Operationen
(bis C++17)(C++11)
(C++20)(C++20)
Stichprobenoperationen
(C++17)

Sortier- und verwandte Operationen
Partitionierungsoperationen
(C++11)    

Sortieroperationen
Binäre Suchoperationen
(auf partitionierten Bereichen)
Mengenoperationen (auf sortierten Bereichen)
Mischoperationen (auf sortierten Bereichen)
Heap-Operationen
Minimum-/Maximum-Operationen
(C++11)
(C++17)
Lexikografische Vergleichsoperationen
Permutationsoperationen


 
Eingeschränkte Algorithmen
Alle Namen in diesem Menü gehören zum Namensraum std::ranges
Nicht modifizierende Sequenzoperationen
Modifizierende Sequenzoperationen
Partitionierungsoperationen
Sortieroperationen
Binäre Suchoperationen (auf sortierten Bereichen)
       
       
Mengenoperationen (auf sortierten Bereichen)
Heap-Operationen
Minimum-/Maximum-Operationen
       
       
Permutationsoperationen
Faltungsoperationen
Operationen auf nicht initialisiertem Speicher
Rückgabetypen
 
Definiert in Header <algorithm>
Aufrufsignatur
template< class T, class Proj = std::identity,
          std::indirect_strict_weak_order<std::projected<const T*, Proj>> Comp =
              ranges::less >
constexpr const T&
    clamp( const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {} );
(seit C++20)

Wenn der Wert von v innerhalb von [lo, hi] liegt, wird v zurückgegeben; andernfalls wird die nächste 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), das heißt:

Parameter

v - der zu begrenzende Wert
lo, hi - die Grenzen, auf die v begrenzt werden soll
comp - der auf die projizierten Elemente anzuwendende Vergleich
proj - die auf v, lo und hi

anzuwendende Projektion

Referenz auf lo, wenn der projizierte Wert von v kleiner als der projizierte Wert von lo ist, Referenz auf hi, wenn der projizierte Wert von hi kleiner als der projizierte Wert von v ist, ansonsten Referenz auf v.

Komplexität

Höchstens zwei Vergleiche und drei Anwendungen der Projektion.

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;

Anmerkungen

Das Erfassen des Ergebnisses von std::ranges::clamp per Referenz erzeugt eine hängende 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 äquivalent zu einer der Grenzen verglichen wird, wird eine Referenz auf v zurückgegeben, nicht auf die Grenze.

Diese Funktion sollte nicht mit einer Projektion, die per Wert zurückgibt, und einem Vergleich verwendet werden, der Argumente per Wert annimmt, es sei denn, eine Verschiebung vom Projektionsergebnis-Typ zum Vergleichsparameter-Typ ist äquivalent zu einer Kopie. Wenn der Vergleich über std::invoke das Ergebnis der Projektion ändern würde, ist das Verhalten aufgrund von den semantischen Anforderungen von std::regular_invocable (subsumiert durch std::indirect_strict_weak_order) undefiniert.

Der Standard verlangt, dass die Wertkategorie des Ergebnisses der Projektion erhalten bleibt, und proj kann nur einmal auf v aufgerufen werden, was bedeutet, dass ein Projektionsergebnis, das ein Prvalue ist, für die beiden Aufrufe des Vergleichs zwischengespeichert und zweimal verschoben werden muss.

  • libstdc++ entspricht dem nicht und übergibt das Projektionsergebnis immer als Lvalue.
  • libc++ führte die Projektion früher zweimal aus, was in Clang 18 korrigiert wurde.
  • MSVC STL führte die Projektion früher zweimal aus, was in VS 2022 17.2 korrigiert wurde.

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

Siehe auch

gibt den kleineren der gegebenen Werte zurück
(Algorithmus-Funktionsobjekt)
gibt den größeren der gegebenen Werte zurück
(Algorithmus-Funktionsobjekt)
(C++20)
prüft, ob ein Integerwert im Bereich eines gegebenen Integer-Typs liegt
(Funktionstemplate)
(C++17)
begrenzt einen Wert zwischen einem Paar von Grenzwerten
(Funktionstemplate)