60 votes

Choisir automatiquement un type de variable assez grand pour contenir un nombre spécifié

Est-il possible en C++ définir un type qui est assez grand pour contenir au plus un nombre spécifique, probablement à l'aide de quelques petits malins de code de modèle. Par exemple: je veux être en mesure d'écrire :-

Integer<10000>::type dataItem;

Et d'avoir ce type de résoudre au plus petit type qui est assez grand pour contenir la valeur spécifiée?

Contexte: j'ai besoin de générer de la variable définitions à l'aide d'un script à partir d'un fichier de données externe. Je suppose que j'ai pu faire le script de regarder les valeurs et ensuite utiliser uint8_t, uint16_t, uint32_t, etc. en fonction de la valeur, mais il semble plus élégant pour construire la taille dans l'généré le code C++.

Je ne vois pas de toute façon de faire d'un modèle qui peut faire cela, mais en sachant que les modèles C++, je suis sûr qu'il ya un moyen. Des idées?

64voto

Georg Fritzsche Points 59185

Coup de pouce.Entier a déjà des installations de Type Entier de Sélection:

boost::int_max_value_t<V>::least

Le plus petit, intégré, signé partie intégrante de type qui peut contenir toutes les valeurs dans la plage de 0 - V. Le paramètre doit être un nombre positif.

boost::uint_value_t<V>::least

Le plus petit, intégrées, non signé de type intégral qui peut contenir toutes les valeurs positives jusqu'à et y compris V. Le paramètre doit être un nombre positif.

49voto

FredOverflow Points 88201

Oui, c'est possible. Voici les ingrédients. Commençons avec mes deux préférés méta-fonctions:

template<uint64_t N>
struct constant
{
    enum { value = N };
};

template<typename T>
struct return_
{
    typedef T type;
};

Ensuite, une méta-fonction qui compte le nombre de bits requis pour stocker un certain nombre:

template<uint64_t N>
struct bitcount : constant<1 + bitcount<(N>>1)>::value> {};

template<>
struct bitcount<0> : constant<1> {};

template<>
struct bitcount<1> : constant<1> {};

Ensuite, une méta-fonction qui compte les octets:

template<uint64_t N>
struct bytecount : constant<((bitcount<N>::value + 7) >> 3)> {};

Ensuite, une méta-fonction qui retourne le plus petit type pour un nombre donné d'octets:

template<uint64_t N>
struct bytetype : return_<uint64_t> {};

template<>
struct bytetype<4> : return_<uint32_t> {};

template<>
struct bytetype<3> : return_<uint32_t> {};

template<>
struct bytetype<2> : return_<uint16_t> {};

template<>
struct bytetype<1> : return_<uint8_t> {};

Et enfin, la méta-fonction qui vous avez demandé:

template<uint64_t N>
struct Integer : bytetype<bytecount<N>::value> {};

27voto

Maxim Yegorushkin Points 29380
#include <stdint.h>

template<unsigned long long Max>
struct RequiredBits
{
    enum { value =
        Max <= 0xff       ?  8 :
        Max <= 0xffff     ? 16 :
        Max <= 0xffffffff ? 32 :
                            64
    };
};

template<int bits> struct SelectInteger_;
template<> struct SelectInteger_ <8> { typedef uint8_t type; };
template<> struct SelectInteger_<16> { typedef uint16_t type; };
template<> struct SelectInteger_<32> { typedef uint32_t type; };
template<> struct SelectInteger_<64> { typedef uint64_t type; };

template<unsigned long long Max>
struct SelectInteger : SelectInteger_<RequiredBits<Max>::value> {};

int main()
{
    SelectInteger<12345>::type x = 12345;
}

7voto

Jack V. Points 992

Voulez-vous nécessairement le plus petit, au lieu d'utiliser int pour les types plus petits que int?

Sinon, et que votre compilateur le supporte, pourriez-vous faire:

 int main()
{
    typeof('A') i_65 = 0; // declare variable 'i_65' of type 'char'
    typeof(10) i_10 = 0; // int
    typeof(10000) i_10000 = 0; // int
    typeof(1000000000000LL) i_1000000000000 = 0; // int 64
}
 

6voto

Kerrek SB Points 194696

Que diriez-vous d'un conditionnel:

 #include <type_traits>
#include <limits>

template <unsigned long int N>
struct MinInt
{
  typedef typename std::conditional< N < std::numeric_limits<unsigned char>::max(),
       unsigned char, std::conditional< N < std::numeric_limits<unsigned short int>::max(),
         unsigned short int>::type,
         void*>::type>::type
    type;
};
 

Cela devrait être étendu pour inclure tous les types souhaités, dans l'ordre; à la dernière étape, vous pourriez utiliser enable_if plutôt que conditional pour avoir une erreur d'instanciation là même si la valeur est trop grande.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X