string_viewoperator+ vs. StrCat()absl::Statusstd::bindabsl::optional and std::unique_ptrabsl::StrFormat()make_unique and private Constructors.boolexplicit= delete)switch Statements Responsibly= deleteAbslHashValue and Youcontains()std::optional parametersif and switch statements with initializersinline Variablesstd::unique_ptr Must Be MovedAbslStringify()vector.at()auto for Variable DeclarationsOriginally posted as TotW #231 on March 7, 2024
Updated 2024-09-30
Quicklink: abseil.io/tips/231
In recent C++ versions the Standard Library has added a few functions whose sole
job is to supply some (specific!) point somewhere between two other points x
and y: std::clamp (from
C++17), and
std::midpoint and
std::lerp (from C++20).
Adding these function templates to the Standard Library serves two main
purposes. First, it establishes common terminology (vocabulary) for these
operations, that is likely to be widely recognized. Second, and particularly in
the case of std::midpoint and std::lerp, it ensures the availability of high
quality implementations that
avoid common pitfalls.
All of these operations are constexpr, meaning that they can be used both at
runtime and at compile time. The types that can be passed to them depend on the
specific operation; they all support floating point types, and std::midpoint
and std::clamp offer additional flexibility. Read on for the details.
std::clampstd::clamp(x, min, max) “clamps” x to the range [min, max]. More
explicitly, if x is already in the range min to max (inclusive) then
std::clamp(x, min, max) returns x, and for x outside of that range
std::clamp returns whichever of min or max is closest to x. This is
equivalent to std::max(std::min(x, max), min) except for being a more direct
way to express the intent (and much less of a puzzle for readers).
Warning: While
std::clampreturns 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 tostd::clampand binding the result to a temporary:// `std::clamp(1, 3, 4)` returns a reference to a temporary int initialized // from `3`, which must not be used beyond the lifetime of the temporary. // See [Tip #101](/tips/101). const int& dangling = std::clamp(1, 3, 4);
std::clamp works for any type that can be compared with < (or with a
user-supplied comparator passed to std::clamp(x, min, max, cmp).
std::midpointThere are no surprises in what std::midpoint does: std::midpoint(x, y)
returns a point halfway between x and y (rounding towards x when x and
y are of an integral type).
std::midpoint(x, y) works for values x, y of any floating point or
integral type (not including bool). As a bonus, std::midpoint(p, q) also
works for pointers p, q into an array.
std::lerpThe lerp in std::lerp is short for “linear interpolation”, and std::lerp(x,
y, t) returns a value some fraction t of the way from x to y. For
example, std::lerp(x, y, 0) returns x, std::lerp(x, y, 1) returns y, and
std::lerp(x, y, 0.5) can be simplified to std::midpoint(x, y).
Note: In spite of the name, std::lerp can also be used for extrapolation if we
pass a value of t outside of the range [0, 1]. For example, std::lerp(100,
101, -2) evaluates to 98, and std::lerp(100, 101, +2) is 102.
std::lerp works on floating point types.
std::midpoint(x, y) over std::lerp(x, y, 0.5) when applicable.std::clamp.