Sponsored Link •
|
Summary
I have recently updated my constrained_value class which among other things allows one to easily define range checking integers.
Advertisement
|
I wanted to share my overhauled constrained_value policy driven class with the community. A constrained_value value type allows you to take an arbitrary value type and define how assignment occurs through a policy parameter. One common usage is to do range checking, but it is much more flexible than this.
The class itself is as follows:
template<class Policy_T> struct constrained_value { public: // public typedefs typedef typename Policy_T policy_type; typedef typename Policy_T::value_type value_type; typedef constrained_value self; // default constructor constrained_value() : m(Policy_T::default_value) { } constrained_value(const self& x) : m(x.m) { } explicit constrained_value(const value_type& x) { Policy_T::assign(m, x); } operator value_type() const { return m; } void assign(const value_type& x) { Policy_T::assign(m, x); } // assignment operations self& operator=(const value_type& x) { assign(x); return *this; } self& operator+=(const value_type& x) { assign(m + x); return *this; } self& operator-=(const value_type& x) { assign(m - x); return *this; } self& operator*=(const value_type& x) { assign(m * x); return *this; } self& operator/=(const value_type& x) { assign(m / x); return *this; } self& operator%=(const value_type& x) { assign(m % x); return *this; } self& operator>>=(int x) { assign(m >> x); return *this; } self& operator<<=(int x) { assign(m << x); return *this; } // unary operations self operator-() { return self(-m); } self operator+() { return self(-m); } self operator!() { return self(!m); } self operator~() { return self(~m); } // binary operations friend self operator+(const self& x, const value_type& y) { return self(x) += y; } friend self operator-(const self& x, const value_type& y) { return self(x) -= y; } friend self operator*(const self& x, const value_type& y) { return self(x) *= y; } friend self operator/(const self& x, const value_type& y) { return self(x) /= y; } friend self operator%(const self& x, const value_type& y) { return self(x) %= y; } friend self operator>>(const self& x, int y) { return self(x) >>= y; } friend self operator<<(const self& x, int y) { return self(x) <<= y; } // comparison operators friend bool operator<(const self& x, const self& y) { return x.m < y.m; } friend bool operator>(const self& x, const self& y) { return x.m > y.m; } friend bool operator<=(const self& x, const self& y) { return x.m <= y.m; } friend bool operator>=(const self& x, const self& y) { return x.m >= y.m; } friend bool operator==(const self& x, const self& y) { return x.m == y.m; } friend bool operator!=(const self& x, const self& y) { return x.m != y.m; } private: value_type m; };
If you want to use this to define a range checking integer, you need to supply a policy such as this one:
template<int Min_N, int Max_N> struct range_throwing_int_policy { typedef int value_type; const static value_type default_value = Min_N; static void assign(value_type& lvalue, const value_type& rvalue) { STATIC_ASSERT(Min_N < Max_N); if ((rvalue < Min_N) || (rvalue > Max_N)) { throw std::range_error("out of valid range"); } lvalue = rvalue; } }; typedef constrained_value<range_throwing_int_policy<0, 6> > weekday; typedef constrained_value<range_throwing_int_policy<0, 23> > hour; typedef constrained_value<range_throwing_int_policy<0, 60> > minute; typedef constrained_value<range_throwing_int_policy<0, 60> > second; typedef constrained_value<range_throwing_int_policy<0, 31> > day; typedef constrained_value<range_throwing_int_policy<0, 11> > month;
More creative policies are also possible, such as assuring that the number is always even or odd:
struct even_numbers_policy { typedef int value_type; const static value_type default_value = 0; static void assign(value_type& lvalue, const value_type& rvalue) { if (rvalue % 2 != 0) { // rounds towards zero if (rvalue > 0) lvalue = rvalue - 1; else lvalue = rvalue + 1; } else { lvalue = rvalue; } } }; struct odd_numbers_policy { typedef int value_type; const static value_type default_value = 1; static void assign(value_type& lvalue, const value_type& rvalue) { if (rvalue % 2 == 0) { // round towards zero policy if (rvalue > 0) lvalue = rvalue - 1; else lvalue = rvalue + 1; } else { lvalue = rvalue; } } }; typedef constrained_value<even_numbers_policy> even_number; typedef constrained_value<odd_numbers_policy> odd_number;
I welcome your comments and improvements.
Have an opinion? Readers have already posted 1 comment about this weblog entry. Why not add yours?
If you'd like to be notified whenever Christopher Diggins adds a new entry to his weblog, subscribe to his RSS feed.
Christopher Diggins is a software developer and freelance writer. Christopher loves programming, but is eternally frustrated by the shortcomings of modern programming languages. As would any reasonable person in his shoes, he decided to quit his day job to write his own ( www.heron-language.com ). Christopher is the co-author of the C++ Cookbook from O'Reilly. Christopher can be reached through his home page at www.cdiggins.com. |
Sponsored Links
|