Here's a reasonably standard and portable way to define int types with an (exact) desired number of bits, in C++. It uses typelists, so you'd best read about those first!

We'll be using a standard C macro, CHAR_BITS, defined in <climits>. And, of course, the standard typelist definitions (a real implementation would just #include Loki's definitions).

#include <climits>

// typelists (from Loki's Typelist.h)
class NullType {};
template <typename H, class T>
struct Typelist {
  typedef H Head;
  typedef T Tail;
};
// #define's for TYPELIST_1, TYPELIST_2, ...; see typelist.
We also need a compile time means for conditional type selection. Loki's Select<flag, IfTrue, IfFalse>::Result fulfills this need:
// Select (from Loki's TypeManip.h)
template<bool flag, typename T, typename U>
struct Select {
  // used when flag is `true'
  typedef T Result;
};
template<typename T, typename U>
struct Select<false, T, U> {
  // specialise when flag is `false'
  typedef U Result;
};
That's all we need from Loki (see Alexandrescu's excellent book Modern C++ Design for the real story; this is just to whet your appetite!).

Now let's define our type. First, we declare a type NoTypeFound, but (unlike NullType above!) we don't define it. The SelectInt template will instantiate using this type only if no appropriate type was found. And thanks to the C++ template rules, it's only if we attempt to instantiate using NoTypeFound that an error will be flagged.

class NoTypeFound;
// only declared -- use will trigger an error!

SelectInt<TL,bits> searches the typelist TL for a type that is exactly bits bits large; SelectInt<TL,bits>::type will be such a type (or NoTypeFound if none such exists).

// Select bits-bits integer from typelist TL
template<class TL, int bits>
struct SelectInt;

template<int bits>
struct SelectInt<NullType, bits> {
  // Empty list -- no type was found!
  typedef NoTypeFound type;
};

template<class Head, class Tail, int bits>
struct SelectInt<Typelist<Head,Tail>, bits> {
  typedef typename
  Select< sizeof(Head)*CHAR_BIT == bits,
          Head,
          typename SelectInt<Tail, bits>::type
        >::Result
  type;
};
Whew! Let's take it one step at a time. TL could be NullType, in which case we generate a type which will flag an error if used (an empty list certainly doesn't contain our desired type!). Or it could be Typelist<Head,Tail>. If so, we check (using Select) if Head has precisely bits bits. If it does, we pick it. Otherwise, we recurse on Tail.

Whatever the result, we typedef it into type.

Now we just have to pass an appropriate typelist to SelectInt:

template<int bits>
class Int {
  // List of types to check
  typedef
    TYPELIST_5(int, signed char, short, long, long long)
    SignedInts;
public:
  typedef typename SelectInt<SignedInts,bits>::type type;
};
That's it! Note, however, that the unlovely long long isn't really standard. So if we include it we're non-standard, and if we don't we probably won't find a Int<64> on most platforms! Still, it beats most alternatives...

To test it, copy all code to a file, then write code such as:

int main()
{
  // Int<17>::type x;    // Compile-time error on any
                         // reasonable platform
  Int<16>::type i2;
  Int<32>::type i4;
  Int<64>::type i8;

  // do stuff, write sizeof's, ...
}

Log in or register to write something here or to contact authors.