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!

Tags:

C++

Stl