std::ranges::clamp() 算法
- 自 C++20 起
- 简化
- 详细
// (1)
constexpr const T&
clamp( const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {} );
参数类型是泛型的,并具有以下约束
T
- (无)Proj
- (无)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 = {} );
-
如果
v
小于lo
,则返回lo
。 -
否则,如果
v
大于hi
,则返回hi
。 -
否则返回
v
。 -
(1) 使用
operator<
比较值。 -
(2) 与 (1) 相同,但使用
comp
比较值。
未定义行为
行为未定义
如果lo
的值大于 hi
。参数
v | 要限制的值。 |
lo hi | 要限制的元素范围。 |
comp | 应用于投影元素的比较操作。 |
proj | 应用于 |
返回值
如果 v
的投影值小于 lo
的投影值,则返回 lo
的引用;如果 hi
的投影值小于 v
的投影值,则返回 hi
的引用;否则返回 v
的引用。
复杂度
最多进行两次比较和三次投影应用。
异常
(无)
可能的实现
clamp(1) 和 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;
备注
未定义行为
如果其中一个参数是临时值且该参数被返回,则通过引用捕获 std::ranges::clamp
的结果会产生悬空引用。
int n = 1;
const int& r = std::ranges::clamp(n - 1, n + 1); // r is dangling
如果 v
与任一边界进行等价比较,则返回 v
的引用,而不是边界的引用。
示例
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';
}
输出
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