Boost logo

Boost :

From: Moore, Paul (paul.moore_at_[hidden])
Date: 2001-11-02 04:38:34


From: helmut.zeisel_at_[hidden]
> To be more exact:
> the documentation of rational_cast does not say what rational_cast
> should do in case when the value is not preserved.
> Clearly this will not happen for built-in types.
> It might, happen, however, for a user defined int
> or an overloaded version of rational_cast.

OK. The semantics of rational_cast are pretty simple (as you will realise).
It's just

    static_cast<FloatType>(numerator) / denominator

There are a couple of things that can go wrong here -

1. The cast IntType -> FloatType may fail or not preserve value
2. The division FloatType / IntType may fail or not preserve value

This excludes silly, but possible, issues like returning a FloatType failing
to preserve values (copy constructor not copying, basically!)

Both of these cases can execute user-defined code, and so in theory,
anything could happen. Obviously, most of the extreme cases are silly, but
this sort of thing often degenerates to constraints like "Types should not
be implemented in a silly way" :-)

Possibly, the simplest thing to do is to document the actual implementation,
and point out the issues. (Effectively, relegating cases (1) and (2) in the
above to the realms of "undefined behaviour").

The only case that really worries me is when an IntType value can't be
represented in a FloatType. But in that case, there's no suitable default
behaviour, and user-defined code for doing the rational->float conversion is
required anyway.

Which leads us on to...

> (Although there is still the open problem
> that rational_cast cannot be overloaded, cf.
>
> http://groups.yahoo.com/group/boost/message/15728 )

Yes, I am still aware of that one. In all honesty, I don't like the "traits"
solution. Traits are a nice idea, especially for library implementers, but I
firmly believe that they are too subtle and complex for the "average"
library user.

Any idiot can convert a rational to a float - the simple approach is the
code in rational_cast. For someone with specialised types, they will have
the specialised knowledge to write their own conversion. All traits buys
them is the ability to *call* that conversion rational_cast. But I can't
honestly believe that they are likely to be using many different rational
types, based on many integer types, and many float types (which is the only
time the genericicity of using the same name really helps). So why not just
write a function?

> Anyway, there are three options where
> this "error_checked_rational_cast" could be:
> in rational.hpp, in (numeric_)cast.hpp
> or in a completely new file.

Or in user code... (Ie, I don't see that this is an important enough
operation to justify a library routine).

> Just to make the benefit of a name change clear:
>
> Consider an algorithm that should work with int and rational:
>
> template<typname Float, typename T> void algorithm(T& t)
> {
> ...
> Float F = xxx_cast<F>(t)
> ...
> }
>
> If T is either int or rational<int>, what should
> "xxx_cast" be?

"my_cast".

Seriously - what is the problem with the user defining a helper function?

I deliberately exposed the numerator() and denominator() member functions to
allow users to write their own functions based on the representation.

I'll add some documentation to the "Conversions" and "Numerator and
Denominator" sections of the documentation to clarify these points.

(Question: Where should I send patches to get them applied?)

Paul.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk