std::ranges::clamp(3)

NAME
std::ranges::clamp - std::ranges::clamp

Synopsis
   Defined in header <algorithm>
   Call signature
   template< class T, class Proj = std::identity,
   std::indirect_strict_weak_order<std::projected<const T*, Proj>> Comp =
   ranges::less > (since
   constexpr const T& C++20)
   clamp( const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {}
   );
   If v compares less than lo, returns lo; otherwise if hi compares less than v,
   returns hi; otherwise returns v.
   The behavior is undefined if lo is greater than hi.
   The function-like entities described on this page are niebloids, that is:
     * Explicit template argument lists may not be specified when calling any of them.
     * None of them is visible to argument-dependent lookup.
     * When one of them is found by normal unqualified lookup for the name to the left
       of the function-call operator, it inhibits argument-dependent lookup.
   In practice, they may be implemented as function objects, or with special compiler
   extensions.

Parameters
   v - the value to clamp
   lo, hi - the boundaries to clamp v to
   comp - the comparison to apply to the projected elements
   proj - the projection to apply to v, lo and hi

Return value
   Reference to lo if the projected value of v is less than the projected value of lo,
   reference to hi if the projected value of hi is less than the projected value of v,
   otherwise reference to v.

Complexity
   At most two comparisons and three applications of the projection.

Possible implementation
   struct clamp_fn {
     template<class T, class Proj = std::identity,
              std::indirect_strict_weak_order<std::projected<const T*, Proj>>
                  Comp = 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);
       return
         std::invoke(comp, std::forward<decltype(pv)>(pv), std::invoke(proj, lo)) ? lo
         : std::invoke(comp, std::invoke(proj, hi), std::forward<decltype(pv)>(pv)) ? hi
         : v;
     }
   };
   inline constexpr clamp_fn clamp;

Notes
   Capturing the result of std::ranges::clamp by reference produces a dangling
   reference if one of the parameters is a temporary and that parameter is returned:
 int n = 1;
 const int& r = std::ranges::clamp(n-1, n+1);
 // r is dangling
   If v compares equivalent to either bound, returns a reference to v, not the bound.

Example
// Run this code
 #include <algorithm>
 #include <cstdint>
 #include <iostream>
 #include <iomanip>
 #include <string>
 using namespace std::literals;
 namespace ranges = std::ranges;
 int main()
 {
     std::cout << " raw clamped to int8_t clamped to uint8_t\n";
     for(int const v: {-129, -128, -1, 0, 42, 127, 128, 255, 256}) {
         std::cout << std::setw(04) << v
                   << std::setw(20) << ranges::clamp(v, INT8_MIN, INT8_MAX)
                   << std::setw(21) << ranges::clamp(v, 0, UINT8_MAX) << '\n';
     }
     std::cout << '\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(04) << v
                   << std::setw(20) << ranges::clamp(v, "-128"s, "127"s, {}, stoi)
                   << std::setw(21) << ranges::clamp(v, "0"s, "255"s, {}, stoi)
                   << '\n';
     }
 }

Output:
  raw clamped to int8_t clamped to uint8_t
 -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

See also
   ranges::min returns the smaller of the given values
   (C++20) (niebloid)
   ranges::max returns the greater of the given values
   (C++20) (niebloid)
   in_range checks if an integer value is in the range of a given integer type
   (C++20) (function template)
   clamp clamps a value between a pair of boundary values
   (C++17) (function template)