2012-08-22 24 views
9

Necesito averiguar el tipo integral sin signo más pequeño que puede representar un número particular, en tiempo de compilación. Algo como esto ...Cómo averiguar el tipo integral más pequeño que puede representar un número, en tiempo de compilación

////////////////////////////////////////////////////////////////////////// 
template<size_t Bits> 
struct uint_least{}; 

template<> 
struct uint_least<8>{ typedef std::uint8_t type; }; 

template<> 
struct uint_least<16>{ typedef std::uint16_t type; }; 

////////////////////////////////////////////////////////////////////////// 
template<size_t max> 
struct uint_least_bits 
{ 
    static const size_t value = 14; // just a placeholder 
}; 

////////////////////////////////////////////////////////////////////////// 
template<size_t max> 
class A 
{ 
    typedef typename uint_least<uint_least_bits<max>::value>::type underlying_type; 

    underlying_type m_X; 
}; 

uint_least tiene la intención de dar al tipo entero sin signo más pequeño que es, al menos, Bits grande y que debería funcionar para cualquier valor hasta 64 (no sólo de 8, 16, 32, 64 pero también 1, 4, 13, etc.).

uint_least_bits está destinado a darle el número mínimo de bits necesarios para representar max.

  • ¿Cómo puedo implementar uint_least?
  • ¿Cómo puedo implementar uint_least_bits?
  • ¿Qué tipos deberían ser bits, min y max? Si la respuesta es un tipo de plantilla, ¿cómo puedo protegerme contra las entradas no válidas?

La estructuración exacta de los rasgos no es importante. Siéntase libre de desechar lo que proporcioné. Solo necesito proporcionar un número y recuperar el tipo integral sin signo más pequeño que pueda contenerlo.

+0

Puedes simplemente usar 'decltype' en tu constante integral. –

+4

¿Debería 'int_least_bits <255, 256> :: value' ser 1 o 9? – GManNickG

+0

@GManNickG Buena pregunta. Yo diría que 9, sin embargo, no dude en estar en desacuerdo y dígame por qué – David

Respuesta

8

Hice esto ayer, qué casualidad. Lo dejo aquí, aunque no es exactamente lo que necesita (que fija el mejor tipo integral de todos modos):

#include <type_traits> 
#include <stdint.h> 

template<size_t i> 
struct best_type { 
    typedef typename std::conditional< 
     (i <= 8), 
     uint8_t, 
     typename std::conditional< 
      (i <= 16), 
      uint16_t, 
      typename std::conditional< 
       (i <= 32), 
       uint32_t, 
       uint64_t 
      >::type 
     >::type 
    >::type type; 
}; 

A continuación, tendrá que utilizar de esta manera:

#include <type_traits> 
#include <iostream> 
#include <stdint.h> 

template<size_t i> 
struct best_type { 
    typedef typename std::conditional< 
     (i <= 8), 
     uint8_t, 
     typename std::conditional< 
      (i <= 16), 
      uint16_t, 
      typename std::conditional< 
       (i <= 32), 
       uint32_t, 
       uint64_t 
      >::type 
     >::type 
    >::type type; 
}; 

int main() { 
    std::cout << sizeof(best_type<2>::type) << std::endl; 
    std::cout << sizeof(best_type<8>::type) << std::endl; 
    std::cout << sizeof(best_type<15>::type) << std::endl; 
    std::cout << sizeof(best_type<17>::type) << std::endl; 
} 

Demostración en vivo, here.

+2

+1 Pero debería obtener crédito por usar 'constexpr' cuando el OP lo esperaba menos. :-) –

4

Si tienes constexpr, esto va a funcionar:

#include <climits> 
#include <cstdint> 
#include <cstddef> 

inline 
constexpr 
unsigned 
clz(unsigned x) 
{ 
    return x == 0 ? sizeof(x)*CHAR_BIT : x & 0x80000000 ? 0 : 1 + clz(x << 1); 
} 

inline 
constexpr 
unsigned 
clp2(unsigned x) 
{ 
    return x == 0 ? 0 : 1 << (sizeof(x)*CHAR_BIT - clz(x-1)); 
} 

inline 
constexpr 
unsigned 
at_least8(unsigned x) 
{ 
    return x < 8 ? 8 : x; 
} 

template<size_t Bits> 
struct uint_least{}; 

template<> 
struct uint_least<8>{ typedef std::uint8_t type; }; 

template<> 
struct uint_least<16>{ typedef std::uint16_t type; }; 

template<> 
struct uint_least<32>{ typedef std::uint32_t type; }; 

template<> 
struct uint_least<64>{ typedef std::uint64_t type; }; 

template<size_t max> 
struct uint_least_bits 
{ 
    static const size_t value = clp2(max); 
}; 

template<size_t max> 
class A 
{ 
    typedef typename uint_least<at_least8(uint_least_bits<max>::value)>::type underlying_type; 

    underlying_type m_X; 
}; 

int main() 
{ 
    A<3> a; 
} 

Si usted no tiene constexpr, se podría traducir CLP2 en un meta-función de plantilla (y lo que queda como ejercicio para el lector :-)).

Descargo de responsabilidad: Asume un 32 bit unsigned. Eso podría generalizarse también si es necesario.

+0

Dime si me equivoco, pero creo que es inútil precisar 'inline' al definir las funciones' constexpr'. – Morwenn

+0

las funciones de constexpr aún se pueden ejecutar en tiempo de ejecución si se llama con argumentos no constexpr. –

+0

Del estándar C++ 11, sección 7.1.5: 'las funciones constexpr y los constructores constexpr están implícitamente en línea'. Ok, eso no tiene nada que ver con el problema actual. Al menos tengo una respuesta para una pregunta. Lo siento por la molestia. – Morwenn

Cuestiones relacionadas