STL function to test whether a value is within some range?
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.
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)};
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!