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, ...
}