std::ranges::clamp() algorithm
- since C++20
- Simplified
- Detailed
// (1)
constexpr const T&
clamp( const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {} );
The type of arguments are generic and have the following constraints:
T- (none)Proj- (none)Comp-std::indirect_strict_weak_order<std::projected<const T*, Proj>>
// (1)
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 = {} );
-
If
vcompares less thanlo, returnslo. -
Otherwise, if
vcompares more thanhi, returnshi. -
Otherwise returns
v. -
(1) Uses
operator<to compare the values. -
(2) Same as (1), but uses
compto compare the values.
The behavior is undefined if the value of lo is greater than hi.
Parameters
v | The value to clamp. |
lo hi | The range of elements to clamp. |
comp | The comparison to apply to the projected elements. |
proj | The projection to apply to |
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.
Exceptions
(none)
Possible implementation
clamp(1) and clamp(2)
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.
Examples
#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';
}
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
Hover to see the original license.