Comunque, per quanto riguarda i tipi a dimensione fissata, nulla che non si possa risolvere con un po' di abuso di metaprogrammazione template e qualche macro:
codice:
#ifndef EXACTWIDTH_HPP_INCLUDED
#define EXACTWIDTH_HPP_INCLUDED
#include <limits>
namespace ExactWidthInt
{
namespace Implementation // Implementazione
{
// Tipo di base usato per registrare i tipi di interi disponibili
template<int Size, bool Signed, unsigned int LineNumber>
struct Imp_ExactBitWidthInt
{
static const bool Defined=false;
};
#define EXACTWIDTH_BEGINTYPETABLE \
const unsigned int Imp_TableFirstLine=__LINE__;
#define EXACTWIDTH_ADDTYPE(type) \
template<> \
struct Imp_ExactBitWidthInt< \
sizeof(type)*std::numeric_limits<unsigned char>::digits,\
std::numeric_limits<type>::is_signed, \
__LINE__ > \
{ \
typedef type T; \
static const bool Defined=true; \
};
#define EXACTWIDTH_ENDTYPETABLE \
const unsigned int Imp_TableLastLine=__LINE__;
// Tabella dei tipi - si inizia con questa macro...
EXACTWIDTH_BEGINTYPETABLE
// Qui in mezzo si mettono tutti i tipi che si vogliono coinvolgere nella ricerca
// Di base metto solo i tipi standard
EXACTWIDTH_ADDTYPE(signed char)
EXACTWIDTH_ADDTYPE(unsigned char)
EXACTWIDTH_ADDTYPE(signed short int)
EXACTWIDTH_ADDTYPE(unsigned short int)
EXACTWIDTH_ADDTYPE(signed int)
EXACTWIDTH_ADDTYPE(unsigned int)
EXACTWIDTH_ADDTYPE(signed long)
EXACTWIDTH_ADDTYPE(unsigned long)
// ... e si finisce con questa
EXACTWIDTH_ENDTYPETABLE
#undef EXACTWIDTH_ADDTYPE
#undef EXACTWIDTH_BEGINTYPETABLE
#undef EXACTWIDTH_ENDTYPETABLE
// Ricerca ricorsiva del tipo che soddisfa le richieste
// Caso generale (mai richiamato, da solo la signature del template e l'argomento di default)
template<int Size, bool Signed, unsigned int LineNumber=Imp_TableFirstLine, bool Found=Imp_ExactBitWidthInt<Size, Signed, LineNumber>::Defined>
struct Imp_FindExactBitWidthInt;
// Tipo trovato: fornisce effettivamente il tipo richiesto come typedef
template<int Size, bool Signed, unsigned int LineNumber>
struct Imp_FindExactBitWidthInt<Size, Signed, LineNumber, true>
{
typedef typename Imp_ExactBitWidthInt<Size, Signed, LineNumber>::T T;
};
// Tipo non trovato: continua la ricerca, passando alla linea successiva
template<int Size, bool Signed, unsigned int LineNumber>
struct Imp_FindExactBitWidthInt<Size, Signed, LineNumber, false>
: Imp_FindExactBitWidthInt<Size, Signed, LineNumber+1>
{
};
// Caso base: tipo non trovato, tabella dei tipi finita; non definisce ::T, così
// si ottiene un errore di compilazione
template<int Size, bool Signed>
struct Imp_FindExactBitWidthInt<Size, Signed, Imp_TableLastLine, false>
{
};
// Tutto il giochino della ricerca anche per linea si rende necessario perché
// più tipi possono avere le medesime dimensioni; se così non fosse, basterebbe
// una tabella dei tipi senza numeri di riga e non sarebbe necessaria la ricerca
// ricorsiva
} // namespace Implementation
// Le due classi da usare per davvero:
// Fornisce come typedef ::T il tipo che corrisponde alla dimensione richiesta (in bit)
// con segno o meno a seconda del secondo parametro
template<int Size, bool Signed>
struct ExactBitWidthInt
{
typedef typename Implementation::Imp_FindExactBitWidthInt<Size, Signed>::T T;
};
// Fornisce come typedef ::T il tipo che corrisponde alla dimensione richiesta (in byte)
// con segno o meno a seconda del secondo parametro
template<int Size, bool Signed>
struct ExactByteWidthInt
{
typedef typename ExactBitWidthInt<Size*std::numeric_limits<unsigned char>::digits, Signed>::T T;
};
}
/*
Esempio:
typedef ExactWidthInt::ExactBitWidthInt<32, false>::T myuint32;
typedef ExactWidthInt::ExactByteWidthInt<2, true>::T my2bytesint;
*/
#endif
È venuto un pelo più complicato del previsto (per via del fatto che più tipi possono avere le stesse dimensioni), ma dovrebbe comunque funzionare bene. La cosa divertente è che se il tipo che corrisponda alle richieste (in termini di bit e di signed/unsigned) non è presente tra quelli della tabella si ha un errore di compilazione.
Per farti un esempio, per avere un intero a 32 bit senza segno basta fare
codice:
ExactWidthInt::ExactBitWidthInt<32, false>::T var;
Naturalmente come notazione è un po' pesante, per cui potresti voler fare una roba del tipo:
codice:
typedef ExactWidthInt::ExactBitWidthInt<32, false>::T UInt32;
typedef ExactWidthInt::ExactBitWidthInt<16, false>::T UInt16;
// ... eccetera
anche per evitare di rischiare l'istanziazione di quella caterva di template ogni volta che vuoi usare una variabile a dimensione fissata.