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:
È 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.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
Per farti un esempio, per avere un intero a 32 bit senza segno basta fare
Naturalmente come notazione è un po' pesante, per cui potresti voler fare una roba del tipo:codice:ExactWidthInt::ExactBitWidthInt<32, false>::T var;
anche per evitare di rischiare l'istanziazione di quella caterva di template ogni volta che vuoi usare una variabile a dimensione fissata.codice:typedef ExactWidthInt::ExactBitWidthInt<32, false>::T UInt32; typedef ExactWidthInt::ExactBitWidthInt<16, false>::T UInt16; // ... eccetera![]()

Rispondi quotando