Skip to main content

std::ranges::clamp() algorithm

// (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>>
  • If v compares less than lo, returns lo.

  • Otherwise, if v compares more than hi, returns hi.

  • Otherwise returns v.

  • (1) Uses operator< to compare the values.

  • (2) Same as (1), but uses comp to compare the values.

Undefined Behaviour

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

Exceptions

(none)

Possible implementation

clamp(1) and clamp(2)
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

Undefined Behaviour

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

Main.cpp
#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
This article originates from this CppReference page. It was likely altered for improvements or editors' preference. Click "Edit this page" to see all changes made to this document.
Hover to see the original license.

std::ranges::clamp() algorithm

// (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>>
  • If v compares less than lo, returns lo.

  • Otherwise, if v compares more than hi, returns hi.

  • Otherwise returns v.

  • (1) Uses operator< to compare the values.

  • (2) Same as (1), but uses comp to compare the values.

Undefined Behaviour

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

Exceptions

(none)

Possible implementation

clamp(1) and clamp(2)
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

Undefined Behaviour

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

Main.cpp
#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
This article originates from this CppReference page. It was likely altered for improvements or editors' preference. Click "Edit this page" to see all changes made to this document.
Hover to see the original license.