ISO: WG21/N0494 ANSI: 94-0107 Author: John Max Skaller Date: May 1994 Reply to: maxtal@suphys.physics.su.oz.au "CHECKED NUMERIC CONVERSIONS" ----------------------------- Numeric conversions in C are not checked, so that demotions sometimes cause changes to seemingly unrelated and possibly unspecified values. Although errors as a result of such demotions are rare, they're quite hard to find when they do occur. Its also difficult sometimes to tell if a conversion is a promotion or demotion, particularly if the operation involves one or more typedef'd or implementation defined types such as "size_t". I propose a small extension to dynamic_cast<>() to permit checked numeric conversions, and much more powerful, but different, generic library function as an alternative. Proposal -------- For conversions amoung including integral types, floating types, enumeration type, and bool, an exception (to be nominated by the LWG) is thrown if the value of the source cannot be represented in the destination: for bool the values 0 and 1 are required. For example: long l = 1000000l; int i = dynamic_cast(l); // exception thrown The cast offers the guarrantee that a conversion A-->B that does not throw an exception may be inverted and the result will be close to the original: "close" means equal except for floating types, where it means the nearest value representable in the target of the dynamic cast. If the conversion is always safe, the compiler can optimise it to remove any run-time penalty. For example: size_t a; long l=dynamic_cast(a); No dynamic check is required on some DOS machines because size_t is 16 bits, while long is 32. Loss of precision in floating demotions does not cause an exception to be thrown: floating values are approximations and coarsening an approximation is not the same thing as obtaining a totally unrelated value due to the effects of modular arithmetic or conversion between signed and unsigned types. For conversions to float, an exception is thrown if the exponent cannot be represented: loss of precision in the mantissa does not cause an exception to be thrown. Note that the dynamic_cast<>() used is a value conversion: double d; dynamic_cast(d); // error dynamic_cast(d); // error dynamic_cast(d); // fine The behaviour of dynamic_cast when the source of a floating conversion is not a valid floating value is undefined. [The LWG should nominate a suitable exception] ALTERNATIVE: Generic Library Function: -------------------------------------- The idea described here is an alternative suggested by Bjarne for a library function: template D invertible_cast(S s) { D d = s; S s2 = d; if(!(s==s2)) throw(non_invertible_conversion()); return s; } This code cant actually be used in a library as it stands, since the result of converting an S to a D in those cases where we want to throw an exception are undefined, so there is no guarrantee that an exception can be thrown. However, the idea seems sound: it requires only that the inverse conversion and both copy constructors be defined, and the source type has an equality operator. Some special magic which only implementors can provide is required to ensure evaluation leads to throwing an exception where undefined behaviour would have been mandated has this been an actual template. As a result, portable implementations of this function are not possible. However, the template notion has the advantage that the code works for user defined types. It has the disadvantage of throwing an exception when a double value is converted to a float, or equivalent user defined operations invoked: however this is clearly implied by the notion of the conversion being invertible. The definition of the function is simple: if the above template would return normally, the library function returns normally, otherwise if an exception (of any kind) would be thrown, the library function throws that exception, otherwise if the results would be undefined, the library function throws a non-invertible-conversion object.