std::ranges::clamp
| Definido en el encabezado <algorithm>
|
||
| Firma de llamada |
||
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 = {} );
|
(desde C++20) | |
Si el valor de v está dentro de [lo, hi], devuelve v; en caso contrario, devuelve el límite más cercano.
El comportamiento no está definido si lo es mayor que hi.
Las entidades similares a funciones descritas en esta página son objetos función de algoritmo (conocidos informalmente como niebloids), es decir:
- No se pueden especificar listas de argumentos de plantilla explícitas al llamar a ninguno de ellos.
- Ninguno de ellos es visible mediante búsqueda dependiente de argumentos.
- Cuando alguno de ellos se encuentra mediante búsqueda no calificada normal como el nombre a la izquierda del operador de llamada a función, se inhibe la búsqueda dependiente de argumentos.
Parámetros
| v | - | el valor a acotar |
| lo, hi | - | los límites entre los que acotar v a
|
| comp | - | la comparación a aplicar a los elementos proyectados |
| proj | - | la proyección a aplicar a v, lo y hi
|
Valor de retorno
Referencia a lo si el valor proyectado de v es menor que el valor proyectado de lo, referencia a hi si el valor proyectado de hi es menor que el valor proyectado de v, en caso contrario referencia a v.
Complejidad
Como máximo dos comparaciones y tres aplicaciones de la proyección.
Posible implementación
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;
|
Notas
Capturar el resultado de std::ranges::clamp por referencia produce una referencia colgante si uno de los parámetros es un temporal y ese parámetro es devuelto:
int n = -1;
const int& r = std::ranges::clamp(n, 0, 255); // r is dangling
Si v compara equivalente a cualquiera de los límites, devuelve una referencia a v, no al límite.
Esta función no debe utilizarse con una proyección que devuelve por valor y un comparador que toma argumentos por valor a menos que una operación move desde el tipo de resultado de la proyección al tipo de parámetro del comparador sea equivalente a una copia. Si la comparación mediante std::invoke cambiara el resultado de la proyección, el comportamiento no está definido debido a los requisitos semánticos de std::regular_invocable (subsumidos por std::indirect_strict_weak_order).
El estándar requiere que se preserve la categoría de valor del resultado de la proyección, y proj solo puede llamarse sobre v una vez, lo que significa que un resultado de proyección que sea un prvalor debe ser almacenado en caché y movido dos veces para las dos llamadas al comparador.
- libstdc++ no cumple con esto y siempre pasa el resultado de la proyección como un lvalor.
- libc++ solía ejecutar la proyección dos veces, lo que se corrigió en Clang 18.
- MSVC STL solía ejecutar la proyección dos veces, lo que se corrigió en VS 2022 17.2.
Ejemplo
#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';
}
Salida:
[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
Véase también
(C++20) |
devuelve el menor de los valores dados (objeto función de algoritmo) |
(C++20) |
devuelve el mayor de los valores dados (objeto función de algoritmo) |
(C++20) |
comprueba si un valor entero está en el rango de un tipo entero dado (plantilla de función) |
(C++17) |
acota un valor entre un par de valores límite (plantilla de función) |