Reputation: 2492
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
Reputation: 7212
This can be done, but not with primitive int
s. 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
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