views:

129

answers:

3

Hi,
according to this question: http://stackoverflow.com/questions/2833730/calling-template-function-without-type-inference the round function I will use in the future now looks like:

template < typename TOut, typename TIn >
TOut roundTo( TIn value ) {
   return static_cast<TOut>( value + 0.5 );
}
   double d = 1.54;
   int i = rountTo<int>(d);

However it makes sense only if it will be used to round to integral datatypes like char, short, int, long, long long int, and it's unsigned counterparts. If it ever will be used with a TOut As float or long double it will deliver s***.

double d = 1.54;
float f = roundTo<float>(d);
// aarrrgh now float is 2.04;

I was thinking of a specified overload of the function but ...
that's not possible...
How would you solve this problem?
many thanks in advance
Oops

A: 

Try using floor:

template < typename TOut, typename TIn >
TOut roundTo( TIn value ) {
   return static_cast<TOut>(floor( value + 0.5 ));
}

double d = 1.54;
int i = rountTo<int>(d);
double d = 1.54;
float f = roundTo<float>(d);
Stephen
+1  A: 

Assuming you want the closest integer value, cast to TOut,

static_cast<TOut>( static_cast<long long>(value + 0.5) );

floor should also work as an alternative to the inner cast. The point is not to rely on the cast to an unknown type to perform any truncation -- ensure the truncation explicitly, with a floor or a cast to a well-known integral type, then perform the further casting you need to return the specified type.

Alex Martelli
I'd really suggest using `floor()`, as using the cast to `long long` will cause undefined behaviour for big numbers.
jpalecek
@jpalecek, since the OP means to use `char`, `short`, and `int` as typical values of `TOut`, the intermediate cast to `long long` can't do any more damage than the final cast to, e.g., `short` will inevitably do afterwards. `floor`'s fine too, of course, but an intermediate cast might be microscopically faster (needs measuring on your specific compiler and platform, of course).
Alex Martelli
@Alex I also mentioned TOut As long long int.
Oops
@Oops, sure, but my point is that, if TOut is any integral type shorter than or equal to long long, the nested static cast can't hurt (if your C++ compiler has integral types longer than that, you could use the longest of those in the nested static cast, of course).
Alex Martelli
A: 

You could disable your function for non-integral return types:

#include <boost/type_traits.hpp>
#include <boost/utility.hpp>

template < typename TOut, typename TIn >
typename boost::enable_if<boost::is_integral<TOut>, TOut>::type roundTo( TIn value ) {
   return static_cast<TOut>( value + 0.5 );
}
Kirill V. Lyadvinsky
Wouldn't a utility that correctly chooses `floor` or `ceil` be handy?
UncleBens