Namespaces
Variants
Views
Actions

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
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.

Contents

[edit] 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

[edit] 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.

[edit] Complexity

At most two comparisons and three applications of the projection.

[edit] 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;

[edit] 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.

[edit] Example

#include <algorithm>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <string>
 
using namespace std::literals;
namespace ranges = std::ranges;
 
int main()
{
    for (std::cout << " raw   clamped to int8_t   clamped to uint8_t\n";
         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

[edit] See also

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