Namespaces
Variants

std::ranges:: clamp

From cppreference.net
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy , ranges::sort , ...
Execution policies (C++17)
Non-modifying sequence operations
Batch operations
(C++17)
Search operations
Modifying sequence operations
Copy operations
(C++11)
(C++11)
Swap operations
Transformation operations
Generation operations
Removing operations
Order-changing operations
(until C++17) (C++11)
(C++20) (C++20)
Sampling operations
(C++17)

Sorting and related operations
Partitioning operations
Sorting operations
Binary search operations
(on partitioned ranges)
Set operations (on sorted ranges)
Merge operations (on sorted ranges)
Heap operations
Minimum/maximum operations
Lexicographical comparison operations
Permutation operations
C library
Numeric operations
Operations on uninitialized memory
Constrained algorithms
All names in this menu belong to namespace std::ranges
Non-modifying sequence operations
Modifying sequence operations
Partitioning operations
Sorting operations
Binary search operations (on sorted ranges)
Set operations (on sorted ranges)
Heap operations
Minimum/maximum operations
Permutation operations
Fold operations
Operations on uninitialized storage
Return types
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 std:: invoke ( proj, v ) está dentro del rango [ std:: invoke ( proj, lo ) , std:: invoke ( proj, hi ) ] , devuelve v ; de lo contrario, devuelve el límite más cercano.

El comportamiento es indefinido si std:: invoke ( proj, lo ) es mayor que std:: invoke ( proj, hi ) .

Las entidades similares a funciones descritas en esta página son algorithm function objects (conocidas informalmente como niebloids ), es decir:

Contenidos

Parámetros

v - el valor a limitar
lo, hi - los límites para limitar 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 , de lo contrario referencia a v .

Complejidad

Como máximo dos comparaciones y tres aplicaciones de la proyección.

Implementación posible

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

Capturing the result of std::ranges::clamp by reference produces a dangling reference if one of the parameters is a temporary and that parameter is returned:
int n = -1;
const int& r = std::ranges::clamp(n, 0, 255); // r está colgando

Si v se compara como 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 retorna por valor y un comparador que toma argumentos por valor a menos que un movimiento 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 pudiera cambiar el resultado de la proyección, el comportamiento es indefinido 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 ser invocado sobre v una vez, lo que significa que un resultado de proyección que es un prvalue debe ser almacenado en caché y movido dos veces para las dos invocaciones al comparador.

  • libstdc++ no cumple con esto y siempre pasa el resultado de la proyección como un lvalue.
  • libc++ solía ejecutar la proyección dos veces, lo cual fue corregido en Clang 18.
  • MSVC STL solía ejecutar la proyección dos veces, lo cual fue corregido 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';
    // Función de proyección
    const auto stoi = [](std::string s) { return std::stoi(s); };
    // Igual que arriba, pero con cadenas
    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)
verifica si un valor entero está en el rango de un tipo entero dado
(plantilla de función)
(C++17)
limita un valor entre un par de valores límite
(plantilla de función)