std::ranges::clamp

From cppreference.com
< cpp‎ | algorithm‎ | ranges
 
 
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy, ranges::sort, ...
Execution policies (C++17)
Non-modifying sequence operations
(C++11)(C++11)(C++11)
(C++17)
Modifying sequence operations
Partitioning operations
Sorting operations
(C++11)
Binary search operations
Set operations (on sorted ranges)
Heap operations
(C++11)
Minimum/maximum operations
(C++11)
(C++17)

Permutations
Numeric operations
Operations on uninitialized storage
(C++17)
(C++17)
(C++17)
C library
 
Constrained algorithms
Non-modifying sequence operations
Modifying sequence operations
Partitioning operations
Sorting operations
Binary search operations
Set operations (on sorted ranges)
Heap operations
Minimum/maximum operations
ranges::clamp

Permutations
Constrained numeric operations
Fold operations
Operations on uninitialized storage
Return types
 
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 >
constexpr const T&

    clamp( const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {} );
(since C++20)

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:

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

#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

returns the smaller of the given values
(niebloid)
returns the greater of the given values
(niebloid)
(C++20)
checks if an integer value is in the range of a given integer type
(function template)
(C++17)
clamps a value between a pair of boundary values
(function template)