By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,234 Members | 1,872 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,234 IT Pros & Developers. It's quick & easy.

An integer type with range checking.

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 range-checked 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.
Jul 23 '05 #1
Share this Question
Share on Google+
11 Replies


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 range-checked 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_
Jul 23 '05 #2

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.

Jul 23 '05 #3

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)?

Jul 23 '05 #4

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
Jul 23 '05 #5

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.
Jul 23 '05 #6

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.

Jul 23 '05 #7

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?
Jul 23 '05 #8

P: n/a
Jason Heyes wrote:

[ ... ]
Would you consider defining operator+ and operator- for bounded?


I've considered going whole-hog 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.

Jul 23 '05 #9

P: n/a
"Jerry Coffin" <jc*****@taeus.com> wrote in message
news:11**********************@f14g2000cwb.googlegr oups.com...

I've considered going whole-hog 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?

Jul 23 '05 #10

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.

Jul 23 '05 #11

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.
Jul 23 '05 #12

This discussion thread is closed

Replies have been disabled for this discussion.