一、基本概念
std::clamp 是 C++17 在 <algorithm> 头文件中引入的一个函数模板。它的作用是将一个值限制在指定的范围内。
函数原型:
1 2 3 4 5
| template< class T > constexpr const T& clamp( const T& v, const T& lo, const T& hi );
template< class T, class Compare > constexpr const T& clamp( const T& v, const T& lo, const T& hi, Compare comp );
|
参数:
v: 要限制的值
lo: 下限
hi: 上限
comp: 可选的比较函数对象
返回值:
- 如果
v 小于 lo,返回 lo
- 如果
v 大于 hi,返回 hi
- 否则,返回
v
其内部的实现类似于如下代码:
1 2 3 4
| template<class T> constexpr const T& clamp(const T& v, const T& lo, const T& hi) { return (v < lo) ? lo : (hi < v) ? hi : v; }
|
注意:
- 必须保证
lo <= hi,否则行为未定义
std::clamp 返回的是引用,这意味着它不会创建新的对象
- 对于自定义类型,需要确保正确重载了比较运算符
二、基本用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <iostream> #include <algorithm>
int main() { std::cout << std::clamp(10, 1, 100) << std::endl; std::cout << std::clamp(0, 1, 100) << std::endl; std::cout << std::clamp(1000, 1, 100) << std::endl;
double pi = 3.14159; std::cout << std::clamp(pi, 3.0, 3.5) << std::endl;
return 0; }
|
三、高级用法
3.1 自定义比较函数
std::clamp 允许我们传入自定义的比较函数,这在处理复杂对象时特别有用。
1 2 3 4 5 6 7 8 9 10 11 12
| #include <iostream> #include <algorithm> #include <string>
int main() { auto cmp = [](const std::string& a, const std::string& b) { return a.length() < b.length(); }; std::string result = std::clamp(std::string("hello"), std::string("a"), std::string("world"), cmp); std::cout << result << std::endl;
return 0; }
|
3.2 与 lambda 表达式结合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #include <iostream> #include <algorithm> #include <vector>
int main() { std::vector<int> numbers = {1, 5, 10, 15, 20}; std::for_each(numbers.begin(), numbers.end(), [](int& n) { n = std::clamp(n, 5, 15); });
for (int n : numbers) { std::cout << n << " "; }
return 0; }
|
3.3 图形编程
在图形编程中,std::clamp 常用于限制颜色值或坐标。
1 2 3 4 5 6 7 8 9
| struct Color { int r, g, b; void normalize() { r = std::clamp(r, 0, 255); g = std::clamp(g, 0, 255); b = std::clamp(b, 0, 255); } };
|
3.4 信号处理,参数读写
在信号处理中,std::clamp 可用于限制信号的幅度。
在参数读写中,std::clamp 可用于保护参数的范围,避免异常数据的写入与读取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| std::vector<double> processSignal(const std::vector<double>& signal, double minAmplitude, double maxAmplitude) { std::vector<double> processedSignal; for (double sample : signal) { processedSignal.push_back(std::clamp(sample, minAmplitude, maxAmplitude)); } return processedSignal; }
template<typename T> void writeParam(T data) { if constexpr (std::is_unsigned<T>::value) { data = std::clamp(v.toUInt(), r.first.toUInt(), r.second.toUInt()); } else if constexpr (std::is_floating_point<T>::value) { data = std::clamp(v.toFloat(), r.first.toFloat(), r.second.toFloat()); } else { data = std::clamp(v.toInt(), r.first.toInt(), r.second.toInt()); } }
|