std::ranges::clamp(3)
π std::ranges::clamp(3) π
hey bestie π this is the std::ranges::clamp(3) page from the C++ Standard Library manual, and itβs giving βkeep your value inside the boundariesβ main character energy. no cap, itβs lowkey iconic.
β¨ 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 >
constexpr const T&
clamp( const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {} );
(since C++20) β¨
If the value of v is within [lo, hi], returns v; otherwise returns the nearest boundary.
bestie, the behavior is undefined iflois greater thanhiβ thatβs not a vibe, do not do it π
The function-like entities described on this page are niebloids, that is:
- Explicit template argument lists cannot be specified when calling any of them.
- None of them are visible to argument-dependent lookup.
- When any of them are found by normal unqualified lookup as the name to the left of the function-call operator, argument-dependent lookup is inhibited.
In practice, they may be implemented as function objects, or with special compiler extensions.
π PARAMETERS π
vβ the value to clamplo,hiβ the boundaries to clampvtocompβ the comparison to apply to the projected elementsprojβ the projection to apply tov,loandhi
πΈ 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. efficient queen behavior fr fr π«Ά
π§ POSSIBLE IMPLEMENTATION π§
struct clamp_fn
{
template<class T, class Proj = std::identity,
std::indirect_strict_weak_order<std::projected<const T*, Proj>>
Comp = std::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);
if (std::invoke(comp, std::forward<decltype(pv)>(pv), std::invoke(proj, lo)))
return lo;
if (std::invoke(comp, std::invoke(proj, hi), std::forward<decltype(pv)>(pv)))
return hi;
return 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, 0, 255); // r is dangling
not the dangling reference π bestie please be careful.
If v compares equivalent to either bound, returns a reference to v, not the bound.
This function should not be used with both a projection that returns by value and comparator that takes arguments by value unless a move from the projection result type to the comparator parameter type is equivalent to a copy. If the comparison via std::invoke would change the result of projection, the behavior is undefined due to the semantic requirements of std::regular_invocable (subsumed by std::indirect_strict_weak_order).
The standard requires that the value category of the result of the projection be preserved, and proj can only be called on v once, which means that a projection result that is a prvalue has to be cached and moved from twice for the two calls to the comparator.
- libstdc++ does not conform to this and always passes the projection result as an lvalue.
- libc++ used to run the projection twice, which was corrected in Clang 18.
- MSVC STL used to run the projection twice, which was corrected in VS 2022 17.2.
π EXAMPLE π
Run this code, bestie π
#include <algorithm>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <string>
using namespace std::literals;
namespace ranges = std::ranges;
int main()
{
std::cout << "[raw] [" << INT8_MIN << ',' << INT8_MAX << "] "
"[0" << ',' << UINT8_MAX << "]\n";
for (int const v : {-129, -128, -1, 0, 42, 127, 128, 255, 256})
std::cout << std::setw(4) << v
<< std::setw(11) << ranges::clamp(v, INT8_MIN, INT8_MAX)
<< std::setw(8) << ranges::clamp(v, 0, UINT8_MAX) << '\n';
std::cout << std::string(23, '-') << '\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(4) << v
<< std::setw(11) << ranges::clamp(v, "-128"s, "127"s, {}, stoi)
<< std::setw(8) << ranges::clamp(v, "0"s, "255"s, {}, stoi)
<< '\n';
}
Output:
[raw] [-128,127] [0,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
-----------------------
-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)
mwah π β source http://cppreference.com, version/date 2024.06.10.
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms