std::ranges::clamp
| Défini dans l'en-tête <algorithm>
|
||
| Signature d'appel |
||
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 = {} );
|
(depuis C++20) | |
Si la valeur de v est comprise entre [lo, hi], retourne v ; sinon retourne la limite la plus proche.
Le comportement est indéfini si lo est supérieur à hi.
Les entités de type fonction décrites sur cette page sont des objets fonctions d'algorithmes (informellement appelés niebloides), c'est-à-dire :
- Les listes d'arguments template explicites ne peuvent pas être spécifiées lors de l'appel de l'un d'entre eux.
- Aucun d'entre eux n'est visible par la recherche dépendante des arguments.
- Lorsque l'un d'entre eux est trouvé par recherche non qualifiée normale comme le nom à gauche de l'opérateur d'appel de fonction, la recherche dépendante des arguments est inhibée.
Paramètres
| v | - | la valeur à clamper |
| lo, hi | - | les limites entre lesquelles clamper v (v)
|
| comp | - | la comparaison à appliquer aux éléments projetés |
| proj | - | la projection à appliquer à v, lo et hi
|
Valeur de retour
Référence à lo si la valeur projetée de v est inférieure à la valeur projetée de lo, référence à hi si la valeur projetée de hi est inférieure à la valeur projetée de v, sinon référence à v.
Complexité
Au plus deux comparaisons et trois applications de la projection.
Implémentation possible
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;
|
Notes
Capturer le résultat de std::ranges::clamp par référence produit une référence pendante si l'un des paramètres est une temporaire et que ce paramètre est retourné :
int n = -1;
const int& r = std::ranges::clamp(n, 0, 255); // r is dangling
Si v est équivalent à l'une ou l'autre limite, retourne une référence à v, pas à la limite.
Cette fonction ne devrait pas être utilisée avec à la fois une projection qui retourne par valeur et un comparateur qui prend des arguments par valeur à moins qu'un déplacement du type de résultat de la projection vers le type de paramètre du comparateur soit équivalent à une copie. Si la comparaison via std::invoke modifie le résultat de la projection, le comportement est indéfini en raison de des exigences sémantiques de std::regular_invocable (subsumées par std::indirect_strict_weak_order).
La norme exige que la catégorie de valeur du résultat de la projection soit préservée, et proj ne peut être appelé sur v qu'une fois, ce qui signifie qu'un résultat de projection qui est une prvalue doit être mis en cache et déplacé deux fois pour les deux appels au comparateur.
- libstdc++ n'est pas conforme à cela et passe toujours le résultat de la projection comme une lvalue.
- libc++ exécutait auparavant la projection deux fois, ce qui a été corrigé dans Clang 18.
- MSVC STL exécutait auparavant la projection deux fois, ce qui a été corrigé dans VS 2022 17.2.
Exemple
#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';
}
Sortie :
[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
Voir aussi
(C++20) |
retourne la plus petite des valeurs données (objet fonction algorithme) |
(C++20) |
retourne la plus grande des valeurs données (objet fonction algorithme) |
(C++20) |
vérifie si une valeur entière est dans l'intervalle d'un type entier donné (modèle de fonction) |
(C++17) |
clamp une valeur entre une paire de valeurs limites (modèle de fonction) |