P: n/a

I would like to be able to extract an integer from a stream without having
to write a test when I want the integer within some range. Unfortunately
there is no rangechecked integer type in the standard C++ library. Consider
the following function:
std::istream &read_range_checked_integer(std::istream &is, int
&result_value)
{
int value;
if (!(is >> value))
{
std::cout << "failed to extract integer" << std::endl;
return is;
}
if (!(value >= 0 && value < 64))
{
std::cout << "extracted integer is out of range" << std::endl;
is.setstate(std::ios_base::failbit);
return is;
}
result_value = value;
return is;
}
I want a type to help write read_range_checked_integer more succinctly. For
example:
std::istream &read_range_checked_integer(std::istream &is, int
&result_value)
{
range_checked_integer<0, 64> value;
if (!(is >> value))
{
std::cout << "failed to extract range_checked_integer<0, 64>" <<
std::endl;
return is;
}
result_value = value.get_int();
return is;
}
Can somebody help me find a type that behaves like range_checked_integer?
Thanks alot.  
Share this Question
P: n/a

Jason Heyes wrote: I would like to be able to extract an integer from a stream without having to write a test when I want the integer within some range. Unfortunately there is no rangechecked integer type in the standard C++ library. Consider the following function:
std::istream &read_range_checked_integer(std::istream &is, int &result_value) { int value; if (!(is >> value)) { std::cout << "failed to extract integer" << std::endl; return is; }
if (!(value >= 0 && value < 64)) { std::cout << "extracted integer is out of range" << std::endl; is.setstate(std::ios_base::failbit); return is; }
result_value = value; return is; }
I want a type to help write read_range_checked_integer more succinctly. For example:
std::istream &read_range_checked_integer(std::istream &is, int &result_value) { range_checked_integer<0, 64> value; if (!(is >> value)) { std::cout << "failed to extract range_checked_integer<0, 64>" << std::endl; return is; }
result_value = value.get_int(); return is; }
Can somebody help me find a type that behaves like range_checked_integer? Thanks alot.
Create a class for ranged integer values and overload the stream
operators. For example:
// rint.h
#ifndef _RINT_H_
#define _RINT_H_
#include <iostream>
class RInt
{
public:
RInt(int min, int max);
virtual ~RInt();
friend std::istream& operator >>(std::istream& s, RInt& i);
friend std::ostream& operator <<(std::ostream& s, const RInt& i);
private:
int value, min, max;
};
// rint.cpp
#include "rint.h"
#include <iostream>
using namespace std;
RInt::RInt(int min, int max) : value (min), min (min), max (max)
{
}
RInt::~RInt()
{
}
istream& operator >>(istream& s, RInt& i)
{
int tmp;
s >> tmp;
if (tmp < i.min  tmp > i.max)
s.clear(s.failbit);
else
i.value = tmp;
return s;
}
ostream& operator <<(ostream& s, const RInt& i)
{
s << i.value;
return s;
}
#endif //_RINT_H_  
P: n/a

Jason Heyes wrote: I would like to be able to extract an integer from a stream without having to write a test when I want the integer within some range.
This may be a bit more elaborate than you were thinking of, but it
should do the job:
// Partially tested code. Compiles and works to at least some degree,
// but may still harbor bugs.
#include <exception>
#include <iostream>
#include <functional>
template <class T, T lower, T upper, class less=std::less<T> >
class bounded {
T val;
static bool check(T const &value) {
return less()(value, lower)  less()(upper, value);
}
public:
bounded() : val(lower) { }
bounded(T const &v) {
if (check(v))
throw std::domain_error("out of range");
val = v;
}
bounded(bounded const &init) : val(init.v) {}
bounded &operator=(T const &v) {
if (check(v))
throw std::domain_error("Out of Range");
val = v;
return *this;
}
operator T() const { return val; }
friend std::istream &operator>>(std::istream &is, bounded &b) {
T temp;
is >> temp;
if (check(temp))
is.setstate(std::ios::failbit);
b.val = temp;
return is;
}
};
The most obvious difference is that this passes the underlying type as
a template parameter instead of making it part of the name. This makes
ranges of various different types about equally easy to work with 
e.g. you can just about as easily do a bounded<double, 0.001, 0.1> as a
bounded<int, 0, 512> like you asked for.

Later,
Jerry.
The universe is a figment of its own imagination.  
P: n/a

"Jerry Coffin" <jc*****@taeus.com> wrote in message
news:11**********************@o13g2000cwo.googlegr oups.com... This may be a bit more elaborate than you were thinking of, but it should do the job:
// Partially tested code. Compiles and works to at least some degree, // but may still harbor bugs. #include <exception> #include <iostream> #include <functional>
template <class T, T lower, T upper, class less=std::less<T> > class bounded { T val;
static bool check(T const &value) { return less()(value, lower)  less()(upper, value); }
public: bounded() : val(lower) { }
bounded(T const &v) { if (check(v)) throw std::domain_error("out of range"); val = v; }
bounded(bounded const &init) : val(init.v) {}
bounded &operator=(T const &v) { if (check(v)) throw std::domain_error("Out of Range"); val = v; return *this; }
operator T() const { return val; }
friend std::istream &operator>>(std::istream &is, bounded &b) { T temp; is >> temp;
if (check(temp)) is.setstate(std::ios::failbit); b.val = temp; return is; } };
The most obvious difference is that this passes the underlying type as a template parameter instead of making it part of the name. This makes ranges of various different types about equally easy to work with  e.g. you can just about as easily do a bounded<double, 0.001, 0.1> as a bounded<int, 0, 512> like you asked for.
Looks good. You allow for implicit conversion between the bounded type and
type T. Why, then, do you need operator=(T const &v)?  
P: n/a

Jason Heyes wrote: "Jerry Coffin" <jc*****@taeus.com> wrote in message news:11**********************@o13g2000cwo.googlegr oups.com... This may be a bit more elaborate than you were thinking of, but it should do the job:
// Partially tested code. Compiles and works to at least some degree, // but may still harbor bugs. #include <exception> #include <iostream> #include <functional>
template <class T, T lower, T upper, class less=std::less<T> > class bounded { T val;
static bool check(T const &value) { return less()(value, lower)  less()(upper, value); }
public: bounded() : val(lower) { }
bounded(T const &v) { if (check(v)) throw std::domain_error("out of range"); val = v; }
bounded(bounded const &init) : val(init.v) {}
bounded &operator=(T const &v) { if (check(v)) throw std::domain_error("Out of Range"); val = v; return *this; }
operator T() const { return val; }
friend std::istream &operator>>(std::istream &is, bounded &b) { T temp; is >> temp;
if (check(temp)) is.setstate(std::ios::failbit); b.val = temp; return is; } };
The most obvious difference is that this passes the underlying type as a template parameter instead of making it part of the name. This makes ranges of various different types about equally easy to work with  e.g. you can just about as easily do a bounded<double, 0.001, 0.1> as a bounded<int, 0, 512> like you asked for.
Looks good. You allow for implicit conversion between the bounded type and type T. Why, then, do you need operator=(T const &v)?
Think of:
bounded< int, 1, 5 > a = 3;
bounded< int, 5, 10 > b = 8;
a = b;

Karl Heinz Buchegger kb******@gascad.at  
P: n/a

"Karl Heinz Buchegger" <kb******@gascad.at> wrote in message
news:42***************@gascad.at... Jason Heyes wrote: Looks good. You allow for implicit conversion between the bounded type and type T. Why, then, do you need operator=(T const &v)?
Think of: bounded< int, 1, 5 > a = 3; bounded< int, 5, 10 > b = 8; a = b;
Oh I see.  
P: n/a

Jason Heyes wrote:
[ ... ] Looks good. You allow for implicit conversion between the bounded type and type T. Why, then, do you need operator=(T const &v)?
Instantiating a template over two different sets of parameters results
in two completely unrelated types. The copy constructor is ONLY used to
assign between two objects of exactly the same type.
As such, without this, assignment from one bounded type to a different
bounded type would involve two type conversions  but only one can be
done implicitly, so all such assignments would require explicit type
casts (which I'd consider undesirable).

Later,
Jerry.
The universe is a figment of its own imagination.  
P: n/a

"Jerry Coffin" <jc*****@taeus.com> wrote in message
news:11**********************@z14g2000cwz.googlegr oups.com... Instantiating a template over two different sets of parameters results in two completely unrelated types. The copy constructor is ONLY used to assign between two objects of exactly the same type.
As such, without this, assignment from one bounded type to a different bounded type would involve two type conversions  but only one can be done implicitly, so all such assignments would require explicit type casts (which I'd consider undesirable).
Would you consider defining operator+ and operator for bounded?  
P: n/a

Jason Heyes wrote:
[ ... ] Would you consider defining operator+ and operator for bounded?
I've considered going wholehog and adding the full range of operators
to it, but so far I've never seen a benefit that justified the work.
OTOH, if somebody else sees it as a worthwhile way to spend their time,
they're certainly more than welcome to take the code and run with it.
In case that wasn't clear: the code is in the public domain, so anybody
can treat it as if they had written it themself, and use it in any way
they please, modify it as they see fit, etc. If I was going to control
it at all, the sole stipulation would be that it never be published as
"free software". I won't try to enforce that, but if you do it, don't
plan on ever being invited to any of my parties. Better yet, make sure
I never know about it. :)

Later,
Jerry.
The universe is a figment of its own imagination.  
P: n/a

"Jerry Coffin" <jc*****@taeus.com> wrote in message
news:11**********************@f14g2000cwb.googlegr oups.com... I've considered going wholehog and adding the full range of operators to it, but so far I've never seen a benefit that justified the work.
As long as I can easily read a bounded type from a stream, I'm happy. :)
Beyond that I don't see the need for a bounded type. For example, I wouldn't
try to replace ordinary ints with bounded ones. Would you?  
P: n/a

Jason Heyes wrote:
[ ... ] As long as I can easily read a bounded type from a stream, I'm happy.
:) Beyond that I don't see the need for a bounded type. For example, I wouldn't try to replace ordinary ints with bounded ones. Would you?
Yes, when it's important that the variable stay within certain bounds.

Later,
Jerry.
The universe is a figment of its own imagination.  
P: n/a

"Jerry Coffin" <jc*****@taeus.com> wrote in message
news:11**********************@l41g2000cwc.googlegr oups.com... Jason Heyes wrote:
[ ... ]
As long as I can easily read a bounded type from a stream, I'm happy. :) Beyond that I don't see the need for a bounded type. For example, I wouldn't try to replace ordinary ints with bounded ones. Would you?
Yes, when it's important that the variable stay within certain bounds.
Often you don't need a bounded type to keep a variable within bounds.   This discussion thread is closed Replies have been disabled for this discussion.   Question stats  viewed: 4263
 replies: 11
 date asked: Jul 23 '05
