# std::clamp

< cpp‎ | algorithm

定义于头文件 `<algorithm>` |  |
template<class T> constexpr const T& clamp( const T& v, const T& lo, const T& hi ); | (1) | (C++17 起)
template<class T, class Compare> constexpr const T& clamp( const T& v, const T& lo, const T& hi, Compare comp ); | (2) | (C++17 起)

1) 若 `v` 小于 `lo` ，则返回 `lo` ；若 `v` 大于 `hi` ，则返回 `hi` ；否则返回 `v` 。使用 operator< 比较值。
2) 同 (1) ，不过使用 `comp` 比较值。

若 `lo` 的值大于 `hi` 则行为未定义。

### 参数

v | - | 要夹住的值
lo,hi | - | 夹 `v` 的边界
comp | - | 比较函数对象（即满足比较 (Compare) 要求的对象），若 `lo` 小于 `v` 且 `v` 小于 `hi`，则返回 ​true 。 比较函数的签名应等价于如下： bool cmp(const Type1 &a, const Type2 &b); 虽然签名不必有 const & ，函数也不能修改传递给它的对象，而且必须接受（可为 const 的）类型 `Type1` 与 `Type2` 的值，无关乎值类别（从而不允许 Type1 & ，亦不允许 Type1 ，除非 `Type1` 的移动等价于复制 (C++11 起)）。 类型 Type1 与 Type2 必须使得 T 类型的对象能隐式转换到这两个类型。 ​
类型要求
- 为使用重载 (1) ， `T` 必须满足可小于比较 (LessThanComparable) 的要求。然而若避免了 `NaN` ，则 `T` 能为浮点类型。

### 返回值

若 `v` 小于 `lo` 到则为 `lo` 的引用，若 `hi` 小于 `v` 则为到 `hi` 的引用，否则为到 `v` 的引用。

### 复杂度

至多二次比较

### 可能的实现

版本一
    template<class T>
    constexpr const T& clamp( const T& v, const T& lo, const T& hi )
    {
        assert( !(hi < lo) );
        return v < lo ? lo : hi < v ? hi : v;
    }
版本二
    template<class T, class Compare>
    constexpr const T& clamp( const T& v, const T& lo, const T& hi, Compare comp )
    {
        assert( !comp(hi, lo) );
        return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
    }

### 注解

若参数之一是临时量，而该参数被返回，则以引用捕获 `std::clamp` 的结果会产生一个悬垂引用：

    int n = -1;
    const int& r = std::clamp(n, 0, 255);
    // r 悬垂

若 `v` 与边界之一比较相等，则返回到 `v` 的引用，而非到边界者。

### 示例

    #include <cstdint>
    #include <algorithm>
    #include <iostream>
    #include <iomanip>
    #include <random>

    int main()
    {
        std::mt19937 g(std::random_device{}());
        std::uniform_int_distribution<> d(-300, 300);
        std::cout << " raw   clamped to int8_t   clamped to uint8_t\n";
        for(int n = 0; n < 5; ++n) {
            int v = d(g);
            std::cout << std::setw(4) << v
                      << std::setw(20) << std::clamp(v, INT8_MIN, INT8_MAX)
                      << std::setw(21) << std::clamp(v, 0, UINT8_MAX) << '\n';
        }
    }

可能的输出：

    .raw   clamped to int8_t   clamped to uint8_t
     168                 127                  168
     128                 127                  128
    -137                -128                    0
      40                  40                   40
     -66                 -66                    0

### 参阅

min | 返回各给定值中的较小者 (函数模板)
max | 返回各给定值中的较大者 (函数模板)
in_range (C++20) | 检查整数值是否在给定整数类型的范围内 (函数模板)
ranges::clamp (C++20) | 在一对边界值间夹一个值 (niebloid)