2009-03-31 24 views
13

estoy usando una plantilla muy conocido para permitir constantes binariasconstante binaria C++/literal

template< unsigned long long N > 
struct binary 
{ 
    enum { value = (N % 10) + 2 * binary<N/10> :: value } ; 
}; 

template<> 
struct binary<0> 
{ 
    enum { value = 0 } ; 
}; 

Así que usted puede hacer algo como binario < 101011011> :: valor. Desafortunadamente, este tiene un límite de 20 dígitos para un largo sin firmar.

¿Alguien tiene una mejor solución?

+0

El límite de 20 es probablemente dependiente del compilador. Depende de cuánta recursión de plantilla tolerará. Algunos compiladores modernos le permitirán pasar un argumento para establecer la máxima profundidad de recursión de la plantilla. –

+3

Pensé que el límite se debía a la cantidad de dígitos decimales que podía almacenar en un largo sin signo, ya que básicamente toma el número * decimal * 101011011 y lo convierte en binario, ¿sí? – paxdiablo

+0

Pax: sí, al menos para GCC que estoy usando. – Unknown

Respuesta

25

¿Esto funciona si usted tiene un cero en su valor binario? Un cero inicial hace el octal constante en lugar de decimal.

Lo que conduce a una forma de exprimir un par de dígitos más de esta solución - ¡siempre comience su constante binaria con un cero! Luego reemplace los 10 en su plantilla con 8.

+2

Ooh, eso es furtivo :-) Bravo. – paxdiablo

+1

¡Gracias chicos, has hecho mi noche! –

4

C++ 0x tiene user-defined literals, que podría utilizarse para implementar lo que está hablando.

De lo contrario, no sé cómo mejorar esta plantilla.

+0

Puede dar un ejemplo. – Unknown

+0

seguro, he aquí un ejemplo: http://stackoverflow.com/questions/537303/binary-literals/538101#538101 –

5

Los enfoques que he utilizado siempre, aunque no tan elegante como la suya:

1/Sólo tiene que utilizar hexagonal. Después de un tiempo, solo tienes que saber qué dígitos hexadecimales representan qué patrones de bits.

2/Use constantes y OR o AGREGUE. Por ejemplo (puede ser necesario calificadores en los patrones de bits para hacerlos sin firmar o larga):

#define b0 0x00000001 
#define b1 0x00000002 
: : : 
#define b31 0x80000000 

unsigned long x = b2 | b7 

3/Si el rendimiento no es crítica y la legibilidad es importante, sólo puede hacerlo en tiempo de ejecución con una función como "x = fromBin (" 101011011 ");".

4/Como una solución astuta, podría escribir un pre-preprocesador que recorra sus archivos * .cppme y cree los * .cpp reemplazando todas las cadenas de tipo "0b101011011" con su equivalente "0x15b" instrumentos de cuerda). No lo haría a la ligera ya que hay todo tipo de complicadas combinaciones de sintaxis de las que puede que tenga que preocuparse. Pero le permitiría escribir su cadena como lo desee sin tener que preocuparse por los caprichos del compilador, y podría limitar la sintaxis con una codificación cuidadosa.

Por supuesto, el siguiente paso después de eso sería el parchar GCC reconocer constantes "0b", sino que puede ser una exageración :-)

+0

divertido, mencionaste la última parte. También estaba usando bitset <> (string (str)). To_ulong() – Unknown

+2

Me pregunto cuál es la situación que hace que el uso de la 'plantilla binaria' sea mejor que simples constantes hexadecimales o 'or-ing' juntas enumeraciones con nombres propios para los bits si estás modelando hardware o protocolos de comunicación? –

+0

En realidad, GCC admite constantes 0b. –

3

Puede añadir más parámetros de plantilla no de tipo "simular" bits adicionales:

// Utility metafunction used by top_bit<N>. 
template <unsigned long long N1, unsigned long long N2> 
struct compare { 
    enum { value = N1 > N2 ? N1 >> 1 : compare<N1 << 1, N2>::value }; 
}; 

// This is hit when N1 grows beyond the size representable 
// in an unsigned long long. It's value is never actually used. 
template<unsigned long long N2> 
struct compare<0, N2> { 
    enum { value = 42 }; 
}; 

// Determine the highest 1-bit in an integer. Returns 0 for N == 0. 
template <unsigned long long N> 
struct top_bit { 
    enum { value = compare<1, N>::value }; 
}; 

template <unsigned long long N1, unsigned long long N2 = 0> 
struct binary { 
    enum { 
     value = 
      (top_bit<binary<N2>::value>::value << 1) * binary<N1>::value + 
      binary<N2>::value 
    }; 
}; 

template <unsigned long long N1> 
struct binary<N1, 0> { 
    enum { value = (N1 % 10) + 2 * binary<N1/10>::value }; 
}; 

template <> 
struct binary<0> { 
    enum { value = 0 } ; 
}; 

Usted puede utilizar esto como antes, por ejemplo:

binary<1001101>::value 

Pero también se puede utilizar el siguiente formas equivalentes:

binary<100,1101>::value 
binary<1001,101>::value 
binary<100110,1>::value 

Básicamente, el parámetro adicional le brinda otros 20 bits para jugar. Puede agregar incluso más parámetros si es necesario.

Dado que el valor posicional del segundo número se usa para determinar qué tan lejos a la izquierda debe desplazarse el primer número, el segundo número debe comenzar con 1. (Esto se requiere de todos modos, ya que se inicia con 0 haría que el número se interpretara como un número octal.)

3
template<unsigned int p,unsigned int i> struct BinaryDigit 
{ 
    enum { value = p*2+i }; 
    typedef BinaryDigit<value,0> O; 
    typedef BinaryDigit<value,1> I; 
}; 
struct Bin 
{ 
    typedef BinaryDigit<0,0> O; 
    typedef BinaryDigit<0,1> I; 
}; 

Permitir:

Bin :: O :: I :: :: I O O :: :: valor

mucho más detallado, pero no hay límites (hasta llegar al tamaño de un int sin firmar por supuesto).

+0

Sneaky! pero ¿no será eso demasiado en vez de solo escribir hexadecimal? – LiraNuna

+4

La extensión obvia sería 'Bin :: OOOO :: IIOO :: IIIO', que podría decirse que es mucho más fácil de leer. – MSalters

3

Técnicamente no es ni C C++, que es una extensión específica del CCG, pero GCC permite binary constants como se ve here:

The following statements are identical: 

i =  42; 
i =  0x2a; 
i =  052; 
i = 0b101010; 

Espero que ayude. Algunos compiladores de Intel y estoy seguro de que otros implementan algunas de las extensiones de GNU. Quizás tengas suerte.

2

Un #define sencilla funciona muy bien:

#define HEX__(n) 0x##n##LU 

#define B8__(x) ((x&0x0000000FLU)?1:0)\ 
       +((x&0x000000F0LU)?2:0)\ 
       +((x&0x00000F00LU)?4:0)\ 
       +((x&0x0000F000LU)?8:0)\ 
       +((x&0x000F0000LU)?16:0)\ 
       +((x&0x00F00000LU)?32:0)\ 
       +((x&0x0F000000LU)?64:0)\ 
       +((x&0xF0000000LU)?128:0) 

#define B8(d) ((unsigned char)B8__(HEX__(d))) 
#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) + B8(dlsb)) 
#define B32(dmsb,db2,db3,dlsb) (((unsigned long)B8(dmsb)<<24) + ((unsigned long)B8(db2)<<16) + ((unsigned long)B8(db3)<<8) + B8(dlsb)) 

B8(011100111) 
B16(10011011,10011011) 
B32(10011011,10011011,10011011,10011011) 

No es mi invención, lo vi en un foro hace mucho tiempo.