patterncppMinor
A class to encapsulate a pair of ints with range-checking
Viewed 0 times
withrangecheckingclassencapsulatepairints
Problem
The goal is to have a helper class to wrap the concept of a resolution safely,
encapsulating the range check into the class, since otherwise it can get lost by
a client not so cautious.
I think this is all the context that's required, but an additional bit of info that may be helpful is that this looks a bit like what Rust does, where you can build restricted types out of the more common ones. Then again, I don't know Rust, and the above is a bit of a gossip that I've heard, so it may be wrong.
Technically it's just a pair of two unsigned integers of some kind (normal or
long etc.), but the type is similar for both, of course. I want to enforce this
as well, so that no one uses two different types by accident, thus instead of
using
alright since it's a hard dependency of the project and I'm sure it won't go
away.
Version one (I think it's suboptimal for the reasons given below):
Header:
Impl:
Bad bad because
someone tries to change it later. Attempt 2, fixing it:
Header:
```
#ifndef RESOLUTION_H
#define RESOLUTION_H
#include
class Resolution {
public:
typedef unsigned int impl_type;
public:
Resolution(impl_type _x, impl_type _y);
static Resolution min();
static Resolution max();
inline i
encapsulating the range check into the class, since otherwise it can get lost by
a client not so cautious.
I think this is all the context that's required, but an additional bit of info that may be helpful is that this looks a bit like what Rust does, where you can build restricted types out of the more common ones. Then again, I don't know Rust, and the above is a bit of a gossip that I've heard, so it may be wrong.
Technically it's just a pair of two unsigned integers of some kind (normal or
long etc.), but the type is similar for both, of course. I want to enforce this
as well, so that no one uses two different types by accident, thus instead of
using
std::pair I use Eigen::Matrix. Eigen isalright since it's a hard dependency of the project and I'm sure it won't go
away.
Version one (I think it's suboptimal for the reasons given below):
Header:
#ifndef RESOLUTION_H
#define RESOLUTION_H
#include
class Resolution {
public:
Resolution(unsigned int _x, unsigned int _y);
static Resolution min();
static Resolution max();
inline unsigned int x() const { return res[0]; }
inline unsigned int y() const { return res[1]; }
protected:
Eigen::Matrix res;
};
#endifImpl:
#include
#include "resolution.h"
Resolution::Resolution(unsigned int _x, unsigned int _y) {
assert(_x min().x() && _y > min().y());
res[0] = _x; res[1] = _y;
}
Resolution Resolution::min() { return Resolution{600, 480}; }
Resolution Resolution::max() { return Resolution{3840, 2160}; }Bad bad because
unsigned int is hardcoded so many times and can get lost ifsomeone tries to change it later. Attempt 2, fixing it:
Header:
```
#ifndef RESOLUTION_H
#define RESOLUTION_H
#include
class Resolution {
public:
typedef unsigned int impl_type;
public:
Resolution(impl_type _x, impl_type _y);
static Resolution min();
static Resolution max();
inline i
Solution
I'd start by separating concerns. To do that, I'd design this as two types. One just restricts an arithmetic type to a range. The other holds a pair of those to form a coordinate. Restricting an arithmetic type to a range might look something like this:
Then a struct to hold a couple of those is trivial:
This would be instantiated something like this:
template
class bounded {
T val;
void assure_range(T v) {
if (v < lower || upper <= v)
throw std::range_error("Value out of range");
}
public:
bounded(bounded const &o) : val(o.val) {}
bounded &operator=(T v) {
assure_range(v);
val = v;
return *this;
}
bounded(T const &v=T()) {
assure_range(v);
val = v;
}
operator T() { return val; }
};Then a struct to hold a couple of those is trivial:
template
struct coordinate {
bounded x;
bounded y;
};This would be instantiated something like this:
coordinate r{1024, 768};Code Snippets
template <class T, T lower, T upper>
class bounded {
T val;
void assure_range(T v) {
if (v < lower || upper <= v)
throw std::range_error("Value out of range");
}
public:
bounded(bounded const &o) : val(o.val) {}
bounded &operator=(T v) {
assure_range(v);
val = v;
return *this;
}
bounded(T const &v=T()) {
assure_range(v);
val = v;
}
operator T() { return val; }
};template<class T, T min_x, T max_x, T min_y, T max_y>
struct coordinate {
bounded<T, min_x, max_x> x;
bounded<T, min_y, max_y> y;
};coordinate<unsigned, 640, 3840, 480, 2160> r{1024, 768};Context
StackExchange Code Review Q#124404, answer score: 3
Revisions (0)
No revisions yet.