std::ranges::clamp
| Определено в заголовке <algorithm>
|
||
| Сигнатура вызова |
||
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 = {} );
|
(начиная с C++20) | |
Если значение v находится в пределах [lo, hi], возвращает v; в противном случае возвращает ближайшую границу.
Поведение не определено, если lo больше, чем hi.
Функциональные объекты, описанные на этой странице, являются объектами-функциями алгоритмов (неформально известными как niebloids), то есть:
- Явные списки аргументов шаблона не могут быть указаны при вызове любого из них.
- Ни один из них не видим при поиске, зависящем от аргументов (ADL).
- Когда любой из них найден с помощью обычного неквалифицированного поиска как имя слева от оператора вызова функции, поиск, зависящий от аргументов (ADL), подавляется.
Параметры
| v | - | значение для зажима |
| lo, hi | - | границы, к которым применяется зажим v
|
| comp | - | сравнение, применяемое к проекции элементов |
| proj | - | проекция, применяемая к v, lo и hi
|
Возвращаемое значение
Ссылка на lo, если проекция значения v меньше, чем проекция значения lo, ссылка на hi, если проекция значения hi меньше, чем проекция значения v, в противном случае ссылка на v.
Сложность
Не более двух сравнений и трех применений проекции.
Возможная реализация
struct clamp_fn
{
template<class T, class Proj = std::identity,
std::indirect_strict_weak_order<std::projected<const T*, Proj>>
Comp = std::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);
if (std::invoke(comp, std::forward<decltype(pv)>(pv), std::invoke(proj, lo)))
return lo;
if (std::invoke(comp, std::invoke(proj, hi), std::forward<decltype(pv)>(pv)))
return hi;
return v;
}
};
inline constexpr clamp_fn clamp;
|
Примечания
Захват результата std::ranges::clamp по ссылке приводит к висячей ссылке, если один из параметров является временным и этот параметр возвращается:
int n = -1;
const int& r = std::ranges::clamp(n, 0, 255); // r is dangling
Если v сравнивается как эквивалентный любой из границ, возвращает ссылку на v, а не на границу.
Эту функцию не следует использовать одновременно с проекцией, возвращающей по значению, и компаратором, принимающим аргументы по значению, если только перемещение из типа результата проекции в тип параметра компаратора не эквивалентно копированию. Если сравнение через std::invoke изменит результат проекции, поведение не определено из-за семантических требований std::regular_invocable (поглощено std::indirect_strict_weak_order).
Стандарт требует, чтобы категория значения результата проекции сохранялась, и proj может вызываться только для v один раз, что означает, что результат проекции, являющийся prvalue, должен быть кэширован и перемещен дважды для двух вызовов компаратора.
- libstdc++ не соответствует этому и всегда передает результат проекции как lvalue.
- libc++ ранее запускал проекцию дважды, что было исправлено в Clang 18.
- MSVC STL ранее запускал проекцию дважды, что было исправлено в VS 2022 17.2.
Пример
#include <algorithm>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <string>
using namespace std::literals;
namespace ranges = std::ranges;
int main()
{
std::cout << "[raw] [" << INT8_MIN << ',' << INT8_MAX << "] "
"[0" << ',' << UINT8_MAX << "]\n";
for (int const v : {-129, -128, -1, 0, 42, 127, 128, 255, 256})
std::cout << std::setw(4) << v
<< std::setw(11) << ranges::clamp(v, INT8_MIN, INT8_MAX)
<< std::setw(8) << ranges::clamp(v, 0, UINT8_MAX) << '\n';
std::cout << std::string(23, '-') << '\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(4) << v
<< std::setw(11) << ranges::clamp(v, "-128"s, "127"s, {}, stoi)
<< std::setw(8) << ranges::clamp(v, "0"s, "255"s, {}, stoi)
<< '\n';
}
Вывод:
[raw] [-128,127] [0,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
-----------------------
-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
Смотрите также
(C++20) |
возвращает меньшее из заданных значений (объект-функция алгоритма) |
(C++20) |
возвращает большее из заданных значений (объект-функция алгоритма) |
(C++20) |
проверяет, находится ли целое значение в диапазоне заданного целого типа (шаблон функции) |
(C++17) |
зажимает значение между парой граничных значений (шаблон функции) |