I have a function: bool inBounds(int value, int low, int high)
. Is there an STL equivalent that does useful things (takes variables of different types, specifically)? I can't find one using Google, and I'd prefer to re-use rather than re-write.
If x is in range, then it must be greater than or equal to low, i.e., (x-low) >= 0. And must be smaller than or equal to high i.e., (high – x) <= 0. So if result of the multiplication is less than or equal to 0, then x is in range.
operator. Returns a Boolean value indicating whether a value is included in a range.
I attempted using the boolean operator && to check the two < and > values if they were true, so that anything between the two numbers would activate the cout statement to print the appropriate message for the numerical value entered.
In C++17, there's no direct equivalent of a function like this, but for smaller types with fast equality comparisons you could use std::clamp
:
if (val == std::clamp(val, low, high)) {
...
}
Alternatively, you can just write your own function to test for this:
template <typename T>
bool IsInBounds(const T& value, const T& low, const T& high) {
return !(value < low) && (value < high);
}
This checks if value
is in the range [low, high). If you want the range [low, high], you'd write this as
template <typename T>
bool IsInBounds(const T& value, const T& low, const T& high) {
return !(value < low) && !(high < value);
}
Note how this is defined purely in terms of operator <
, which means that any class that supports just operator <
can be used here.
Similarly, here's one using custom comparators:
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);
}
This latter one has the nice advantage that low
and high
don't have to be the same type as value
, and as long as the comparator can handle that it will work just fine.
Hope this helps!
You could compose one from std::less
, std::more
, std::bind
and std::compose
, but that's truly overkill.
Lambda's are far easier:
[](int value, int low, int high){return !(value < low) && (value < high);}
or, if low and high are in scope
[low, high](int value){return !(value < low) && (value < high)};
bool inBounds(int value, int low, int high)
has the slight drawback that you have to remember which parameter goes where.
I can't be the only one whose perfectly rational parameter ordering is bewildering when returning to code after some time.
You could go the extra mile and define
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); }
Then you can be more explicit about what you mean:
if (interval(a, b).contains(value))
// ...
If one is in abstraction mode it's not too hard to generalise to accomodate different inclusive/exclusive combinations.
Of course this might be overkill for your purposes.
YMMV, and all that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With