Namespaces
Variants

std::ranges::clamp

De es.cppreference.net
 
 
Biblioteca de algoritmos
Algoritmos restringidos y algoritmos sobre rangos (C++20)
Algoritmos restringidos, ej. ranges::copy, ranges::sort, ...
Operaciones de secuencia no modificadoras    
Operaciones por lotes
(C++17)
Operaciones de búsqueda
Operaciones de secuencia modificadoras
Operaciones de copia
(C++11)
(C++11)
Operaciones de intercambio
Operaciones de transformación
Operaciones de generación
Operaciones de eliminación
Operaciones de cambio de orden
(hasta C++17)(C++11)
(C++20)(C++20)
Operaciones de muestreo
(C++17)

Ordenamiento y operaciones relacionadas
Operaciones de particionado
(C++11)    

Operaciones de ordenamiento
Operaciones de búsqueda binaria
(en rangos particionados)
Operaciones de conjunto (en rangos ordenados)
Operaciones de fusión (en rangos ordenados)
Operaciones de montículo
Operaciones de mínimo/máximo
(C++11)
(C++17)
Operaciones de comparación lexicográfica
Operaciones de permutación


 
Algoritmos restringidos
Todos los nombres en este menú pertenecen al espacio de nombres std::ranges
Operaciones de secuencia no modificadoras
Operaciones de secuencia modificadoras
Operaciones de particionado
Operaciones de ordenamiento
Operaciones de búsqueda binaria (en rangos ordenados)
       
       
Operaciones de conjunto (en rangos ordenados)
Operaciones de montículo
Operaciones de mínimo/máximo
       
       
Operaciones de permutación
Operaciones de pliegue
Operaciones en almacenamiento no inicializado
Tipos de retorno
 
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:

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

devuelve el menor de los valores dados
(objeto función de algoritmo)
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)