J'ai une fonction : bool inBounds(int value, int low, int high)
. Existe-t-il un équivalent STL qui fasse des choses utiles (qui prenne des variables de différents types, en particulier) ? Je n'arrive pas à en trouver un en utilisant Google, et je préfère réutiliser plutôt que réécrire.
Réponses
Trop de publicités?En C++17, il n'y a pas d'équivalent direct d'une telle fonction, mais pour les petits types avec des comparaisons d'égalité rapides, vous pouvez utiliser std::clamp
:
if (val == std::clamp(val, low, high)) {
...
}
Vous pouvez également écrire votre propre fonction pour tester cela :
template <typename T>
bool IsInBounds(const T& value, const T& low, const T& high) {
return !(value < low) && (value < high);
}
Il s'agit de vérifier si value
est compris dans l'intervalle [faible, élevé]. Si vous voulez l'intervalle [low, high], vous écrirez cela comme suit
template <typename T>
bool IsInBounds(const T& value, const T& low, const T& high) {
return !(value < low) && !(high < value);
}
Notez qu'elle est définie uniquement en termes de operator <
ce qui signifie que toute classe qui ne supporte que les operator <
peut être utilisé ici.
De même, en voici un qui utilise des comparateurs personnalisés :
template <typename T, typename R, typename Comparator>
bool IsInBounds(const T& value, const R& low, const R& high, Comparator comp) {
return !comp(value, low) && comp(value, high);
}
Cette dernière a l'avantage de low
y high
ne doivent pas nécessairement être du même type que les value
et tant que le comparateur peut gérer cela, il fonctionnera parfaitement.
J'espère que cela vous aidera !
bool inBounds(int value, int low, int high)
a le léger inconvénient de vous obliger à vous rappeler quel paramètre va où.
Je ne peux pas être le seul dont l'ordre parfaitement rationnel des paramètres est déconcertant lorsque l'on revient au code après un certain temps.
Vous pouvez aller plus loin et définir
template<typename T>
class Interval
{
public:
Interval(T lo, T hi) : low(lo), high(hi) {}
bool contains(T value) const { return low <= value && value < high; }
private:
T low;
T high;
};
template<typename T>
Interval<T> interval(T lo, T hi) { return Interval<T>(lo, hi); }
Vous pouvez alors être plus explicite sur ce que vous voulez dire :
if (interval(a, b).contains(value))
// ...
Si l'on est en mode abstraction, il n'est pas trop difficile de généraliser pour accommoder différentes combinaisons inclusives/exclusives.
Bien entendu, cela peut s'avérer excessif pour vos besoins.
YMMV, et tout le reste.
Vous pouvez en composer un à partir de std::less
, std::more
, std::bind
y std::compose
mais c'est vraiment exagéré.
Les lambdas sont beaucoup plus faciles à utiliser :
[](int value, int low, int high){return !(value < low) && (value < high);}
ou, si les valeurs basse et haute sont comprises dans le champ d'application
[low, high](int value){return !(value < low) && (value < high)};
Je pense qu'il serait préférable de ne pas tenter une tâche aussi triviale avec une fonction entière et de simplement intégrer le comportement.
Voici ce qu'il en est :
int main()
{
int value = 5;
int lower = 0;
int upper = 10;
bool inside = lower < value && value < upper;
std::cout << "inside: " << inside;
}
Si vous avez une raison de ne pas écrire le code simplement de cette manière, veuillez m'en faire part et je pourrai vous fournir une réponse plus sophistiquée.