If you want something to work well on every integer type, you can embed this in a trait built in several steps. We begin by mapping integral types with their bit size:
#define CREATE_SIGNED_META_OBJ(x) template <>\
struct signed_integer_type<x> {\
typedef int##x##_t type;\
};
#define CREATE_UNSIGNED_META_OBJ(x) template <>\
struct unsigned_integer_type<x> {\
typedef uint##x##_t type;\
};
template <std::size_t length>
struct signed_integer_type;
template <std::size_t len>
struct unsigned_integer_type;
CREATE_SIGNED_META_OBJ(8)
CREATE_SIGNED_META_OBJ(16)
CREATE_SIGNED_META_OBJ(32)
CREATE_SIGNED_META_OBJ(64)
CREATE_UNSIGNED_META_OBJ(8)
CREATE_UNSIGNED_META_OBJ(16)
CREATE_UNSIGNED_META_OBJ(32)
CREATE_UNSIGNED_META_OBJ(64)
Then, the trait in itself can be built. We want to apply our dichotomy on the value of the assertion std::numeric_limits<Int>::min() == 0
...
template <typename Int, bool>
struct get_smallest_for_max_plus_one;
template <typename Int>
struct get_smallest_for_max_plus_one<Int, true> {
typedef typename signed_integer_type<2*sizeof(Int)*8>::type type;
};
template <typename Int>
struct get_smallest_for_max_plus_one<Int, false> {
typedef typename unsigned_integer_type<sizeof(Int)*8>::type type;
};
template <typename Int>
using get_fittest_int_type = get_smallest_for_max_plus_one<Int, std::numeric_limits<Int>::min() == 0>;
Now we can use directly get_fittest_int_type
with any integral integer... Running examples can be found on Coliru.
For consistency's sake though, I guess you want to keep the signed
or unsigned
property... If this is the case, you could just replace the specializations of get_smallest_for_max_plus_one
with the following:
// Unsigned type, we want to get the smallest unsigned type that can hold max + 1
template <typename Int>
struct get_smallest_for_max_plus_one<Int, true> {
typedef typename unsigned_integer_type<2*sizeof(Int)*8>::type type;
};
// Signed type, we want the smallest signed type that can hold max + 1
template <typename Int>
struct get_smallest_for_max_plus_one<Int, false> {
typedef typename signed_integer_type<2*sizeof(Int)*8>::type type;
};