Anon
Anon

Reputation: 2492

How to set min/max values for an integer, where `++` and `--` and general math obeys the limits you set, in c++?

Rather than litter my code with a ton of if statements, I would like to know a clean method for setting limits on an integer, that will still wrap its value when iterating over those limits.

So for example,

int i(9998);
setMinMax(i,-27315, 10000); // Absolute Zero - Boiling Point of water
i++; // ==  9999
i++; // ==  10000
i++; // == -27315

If the min-max values can be dynamic, that would be ideal. I do not mind making a new type, or operator overloading. I just want to avoid having to do something like this:

int i = foo();
int j = bar();
int min(-27315);
int max(10000);
i += j;
     if (i==min-1) {i=max}
else if (i==max+1) {i=min}
else if (i>max) {i=min+(i-max)}
// more stupid code

Thanks.

Upvotes: 1

Views: 1028

Answers (2)

alter_igel
alter_igel

Reputation: 7212

This can be done, but not with primitive ints. You'll need to implement your own class type that overloads various arithmetic operators in order to look and feel just like an int. Here's one way you could achieve this:

#include <limits> // for numeric_limits

struct RangedInt {
private:
    int m_min = std::numeric_limits<int>::min();
    int m_max = std::numeric_limits<int>::max();
    int m_val = 0;
public:
    RangedInt(int value = 0) : m_val(value) {}

    void setMinMax(int min, int max){
        m_min = min;
        m_max = max;
        m_val = std::min(std::max(m_val, m_min), m_max);
    }

    // pre-increment
    RangedInt& operator++(){
        m_val++;
        if (m_val > m_max) m_val = m_min;
        return *this;
    }

    // post-increment
    RangedInt operator++(int){
        RangedInt tmp {*this}; // create temporary with old value
        operator++(); // perform increment
        return tmp; // return temporary
    }

    // pre-decrement
    RangedInt& operator--(){
        m_val--;
        if (m_val < m_min) m_val = m_max;
        return *this;
    }

    // post-decrement
    RangedInt operator--(int){
        RangedInt tmp {*this}; // create temporary with old value
        operator--(); // perform decrement
        return tmp; // return temporary
    }

    // this can be extended to implement the following operators
    RangedInt operator+(const RangedInt& x);
    RangedInt operator+(int x);
    RangedInt operator-(const RangedInt& x);
    RangedInt operator-(int x);
    RangedInt& operator+=(const RangedInt& x);
    RangedInt& operator+=(int x);
    RangedInt& operator-=(const RangedInt& x);
    RangedInt& operator-=(int x);
    // and lots more, for *, /, unary +/-, etc...

    // convenient conversion to int:
    explicit operator int(){
        return m_val;
    }
};

The above code now lets you write the following:

RangedInt i = 9998;
i.setMinMax(-27135, 10000);
std::cout << (int)i << '\n'; // 9998
i++;
std::cout << (int)i << '\n'; // 9999
i++;
std::cout << (int)i << '\n'; // 10000
i++;
std::cout << (int)i << '\n'; // -27135

This method can be extended with templates to work for any numeric type and not just int, and you could also turn the minimum and maximum values into template parameters, if they're known at compile time and memory footprint is a concern.

Upvotes: 5

ravnsgaard
ravnsgaard

Reputation: 932

You may want to look at Jonathan Müller's type_safe library and associated blog post. It provides a framework to do (among many other things) what you're looking for here.

Upvotes: 1

Related Questions