I’m trying to write a branchless function to return the MAX or MIN of two integers without resorting to if (or ?:). Using the usual technique I can do this easily enough for a given word size:
inline int32 imax( int32 a, int32 b ) { // signed for arithmetic shift int32 mask = a - b; // mask < 0 means MSB is 1. return a + ( ( b - a ) & ( mask >> 31 ) ); }
Now, assuming arguendo that I really am writing the kind of application on the kind of in-order processor where this is necessary, my question is whether there is a way to use C++ templates to generalize this to all sizes of int.
The >>31 step only works for int32s, of course, and while I could copy out overloads on the function for int8, int16, and int64, it seems like I should use a template function instead. But how do I get the size of a template argument in bits?
Is there a better way to do it than this? Can I force the mask T to be signed? If T is unsigned the mask-shift step won’t work (because it’ll be a logical rather than arithmetic shift).
template< typename T > inline T imax( T a, T b ) { // how can I force this T to be signed? T mask = a - b; // I hope the compiler turns the math below into an immediate constant! mask = mask >> ( (sizeof(T) * 8) - 1 ); return a + ( ( b - a ) & mask ); }
And, having done the above, can I prevent it from being used for anything but an integer type (eg, no floats or classes)?
EDIT: This answer is from before C++11. Since then, C++11 and later has offered
make_signed<T>and much more as part of the standard libraryGenerally, looks good, but for 100% portability, replace that 8 with
CHAR_BIT(ornumeric_limits<char>::max()) since it isn’t guaranteed that characters are 8-bit.Any good compiler will be smart enough to merge all of the math constants at compile time.
You can force it to be signed by using a type traits library. which would usually look something like (assuming your numeric_traits library is called numeric_traits):
An example of a manually rolled numeric_traits header could look like this: http://rafb.net/p/Re7kq478.html (there is plenty of room for additions, but you get the idea).
or better yet, use boost:
EDIT: IIRC, signed right shifts don’t have to be arithmetic. It is common, and certainly the case with every compiler I’ve used. But I believe that the standard leaves it up the compiler whether right shifts are arithmetic or not on signed types. In my copy of the draft standard, the following is written:
But as I said, it will work on every compiler I’ve seen :-p.