Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

STL function to test whether a value is within some range?

Tags:

c++

stl

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.

like image 787
simont Avatar asked Feb 13 '12 05:02

simont


People also ask

How to make sure a number is within a range?

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.

Which operator is used to test whether a given value is included in the range?

operator. Returns a Boolean value indicating whether a value is included in a range.

How do you check if a value is between two numbers in C++?

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.


3 Answers

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!

like image 95
templatetypedef Avatar answered Sep 21 '22 21:09

templatetypedef


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)};

like image 45
MSalters Avatar answered Sep 21 '22 21:09

MSalters


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.

like image 33
molbdnilo Avatar answered Sep 21 '22 21:09

molbdnilo