(原文链接:https://abseil.io/tips/231 译者:clangpp@gmail.com)
每周贴士 #231: 少用Flags,尤其是在库代码中
- 最初发布于:2024-03-07
- 作者:James Dennett
- 更新于:2024-09-30
- 短链接:abseil.io/tips/231
概述
最近的一些C++版本中,标准库加入了一些函数,他们的唯一任务就是提供两点(x和y)之间的一些(特定的)点:std::clamp (来自C++17)std::midpoint和std::lerp(来自C++20)。
把这些函数模板加入标准库有两个目的。第一,统一这些操作的术语——这点很容易被认识到;第二,特别是std::midpoint和std::lerp的情况,它提供了高质量的实现以避免常见的错误。
所有这些操作都是constexpr,意味着既能用在运行期又能用在编译期。支持的输入数据类型取决于特定的操作,而且std::midpoint和std::clamp还提供了额外的灵活性。详情如下。
std::clamp
std::clamp(x, min, max)把x“夹”在区间[min, max]以内。更直白地说,如果x已经在min到max之间(含两点),那么std::clamp(x, min, max)返回x;对于落在此区间之外的x,std::clamp返回min或max中距x最近的那个值。这个操作等价于std::max(std::min(x, max), min),只是更直接地表达目的(也少了很多给读者的谜语代码)。
警告:虽然std::clamp返回引用,但是依赖此行为的代码是隐晦和不常见的,而且需要给读者一个注释作为警报。传给std::clamp一个临时变量并且绑定返回值到一个临时变量,很容易不小心创建一个悬挂引用:
// `std::clamp(1, 3, 4)`返回一个指向临时变量的引用,该临时变量初始化自`3`,不应该超越该临时变量的生命周期使用。
// 参阅 See [Tip #101](https://abseil.io/tips/101).
const int& dangling = std::clamp(1, 3, 4);
std::clamp适用于任何可以用<比较大小的类型(或传一个用户提供的比较器std::clamp(x, min, max, cmp))。
Warning: While std::clamp returns a reference, code depending on that is subtle and unusual, and would warrant a comment to alert readers. It is easy to accidentally create a dangling reference by passing a temporary to std::clamp and binding the result to a temporary:
std::midpoint
std::midpoint干的事儿没什么惊喜:std::midpoint(x, y)返回x和y的中点(x和y是整数的话,向x方向取整)。
std::midpoint(x, y)适用于任何浮点型或整型(不含bool)。买一送一,std::midpoint(p, q)还适用于指向数组元素的指针p, q。
std::lerp
std::lerp中的“lerp”是“linear interpolation”(线性插值)的缩写。std::lerp(x, y, t)返回从x到y之间t分数距离的值。例如,std::lerp(x, y, 0)返回x,std::lerp(x, y, 1)返回y,std::lerp(x, y, 0.5)可以被简化为std::midpoint(x, y)。
注:别看它的起名(译者注:叫内插(interpolation)),当输入t超过[0, 1]区间的时候,std::lerp还可以用作外插(extrapolation)。例如,std::lerp(100, 101, -2)取值是98, std::lerp(100, 101, +2)是102。
std::lerp适用于浮点型。
建议
- 这些库函数的主要好处之一是提供共同的术语。跟以往一样,推荐使用这些标准的工具,而不是从头发明轮子。
- 任何合适的时候,使用
std::midpoint(x, y)而不是std::lerp(x, y, 0.5)。 - 避免声明引用指向
std::clamp的返回值。

882

被折叠的 条评论
为什么被折叠?



