Boost logo

Boost Users :

Subject: Re: [Boost-users] [boost] [review][constrained_value] Review ofConstrainedValueLibrary begins today
From: Robert Kawulak (robert.kawulak_at_[hidden])
Date: 2008-12-07 17:45:19


Hi Jesse,
 
> From: jesseperla_at_[hidden]

First, I hope that you are aware of the issues with using floating point types
with this library. If not, please read the rationale section of the
documentation and the discussion in the related thread on the developers' list.

> > OK, now it makes a bit more sense. Moreover, I believe it is possible
(though
> > maybe not trivial) to implement something similar with the current
library.
> Cool. This would be necessary for me to use the library, so I hope it is
possible to have dynamic bounds associated with the type. If this was completed,
would the space/storage taken up by an instantiation of the bounded type be the
same as the underlying type?

Yes, provided you use a zero-size constraint class and your compiler is
opimising well (see http://article.gmane.org/gmane.comp.lib.boost.devel/183612).

The constraint could look like this (written out of my head, not tested):

        template<typename Tag, typename T, typename C = std::less<T> >
        struct static_within_bounds
        {
                typedef T bounds_type;
                typedef within_bounds<T, T, bool, bool, C> within_bounds_type;
                
                static within_bounds_type & get_bounds()
                {
                        assert( !_bounds_used );
                        return _bounds;
                }

                static const within_bounds_type & get_bounds_const()
                {
                        return _bounds;
                }

                bool operator () (const bounds_type & value) const
                {
                        _bounds_used = true;
                        return get_bounds_const()(value);
                }

        private:
                static within_bounds_type _bounds;
                static bool _bounds_used;
        };

Then you define the bounds like this:

        struct interest_rate_tag;
        typedef static_within_bounds<interest_rate_tag, int>
interest_rate_bounds;
        interest_rate_bounds::get_bounds().lower_bound() = 5;
        interest_rate_bounds::get_bounds().upper_bound() = 10;

And once you've defined the bounds, you create and use bounded objects:

        typedef constrained<interest_rate_bounds::bounds_type,
interest_rate_bounds> interest_rate;
        interest_rate x(7);
        x = 3; // exception!
        interest_rate_bounds::get_bounds().lower_bound() = 3; // assertion!

You can query the bounds this way:

        if( x.constraint().get_bounds_const().lower_bound() == 5 )
                // ...

Or:

        if( interest_rate::get_bounds_const().lower_bound() == 5 )
                // ...

> so that I could potentially pass on a pointer to a C function for some
interoperability

Ouch. :P

> For example, would something like the following work to ensure consistency in
my own usage?:
> template<typname T>
> void myfunc1(T& t)
> {
> cout << std::max(0.0, static_cast<double>(t)); //Note a floating point
here
> }

Yes, explicit casts will work for both constrained and underlying type values.

> Does the constrained value only have a direct cast to its underlying type, or
is there any way to have it cast to any types that the underlying type can cast
to?

It has a cast to the underlying type, but then the underlying type may be
convertible to some other type, so:

        constrained<double> x;
        static_cast<int>(x);

...will work (conversions are constrained<double> -> double -> int).

> 3) Bounds including infinity?::::::::
> When we are working with bounds, can we use the numeric infinities with
both open and closed sets? I am thinking something like:
> typedef bounded_type<double, "Risk Aversion"> risk_aversion;
> risk_aversion::change_bounds(1,
std::numeric_limits<double>::infinity()); //Might want open or closed depending
on if function domain is reals or extended reals.

Yes, if you really want to use floating point types (even though this is
discouraged), you can do this.
        
> 4) Numeric limits traits?::::::::::::
> What would be really useful is if bounded<> and other types would
generate traits on their own based on the underlying type... this way, we
wouldn't have to create numeric_limits traits for the types ourselves (which is
unreasonable for a library user).

Why not just use numeric_limits<risk_aversion::value_type>?
        
> 5) Testing set inclusion::::::::
> While it is nice to have the bounds checking on the () operator, I would
also want to be able to ask the type if a value is in the set. For example, in
math:

if( risk_aversion::get_bounds_const().is_within(3) )
        // ...

> 6) No debug only functionality please::::::::::::
> On all of the conversations about turning off bounds checking on debug,
I would definitely not want this to happen automatically. And a bounds checking
failure should be an exception, not a non-recoverable error.

This is how the default error policy works.
        
> 7) Operations consistent with built in C++ numeric
types:::::::::::::::::::
> You have successfully educated me on why you need to overload the ++,
--, +, -, etc. operators yourself and can't just revert to the underlying type.

Actually, only the mutating operators (++, --, =, += etc.) are overloaded. For
the rest, the underlying type's operator can be used.

> But focusing entirely on intrinsic numeric types double, int, etc.: Will we
have complete coverage of the operators that are defined for these types in C++?

I don't think this is needed. If you write:

        constrained<int> x, y, z;
        z = x + y;

Then simply the + operator for int is used.

> Will the compiler end up generating EXACTLY the same code if I do a whole
bunch of read only operations on a bounded<double> vs. a double?

Quite possibly.

Best regards,
Robert


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net