Pregunta

Me estoy preparando para la definición de literales definidos por el usuario con un Plantilla variádica

template<...>
unsigned operator "" _binary();

unsigned thirteen = 1101_binary;

GCC 4.7.0 no admite operator "" Sin embargo, pero puedo simular esto con una función simple hasta entonces.

Por desgracia, mi recursión es la forma incorrecta. No puedo pensar en una buena manera de cómo No cambie los valores más a la derecha, sino la izquierda más:

template<char C> int _bin();
template<>       int _bin<'1'>() { return 1; }
template<>       int _bin<'0'>() { return 0; }

template<char C, char D, char... ES>
int _bin() {
    return _bin<C>() | _bin<D,ES...>() << 1; // <-- WRONG!
}

Lo que por supuesto no está del todo bien:

int val13 = _bin<'1','1','0','1'>();  // <-- gives 10

Porque mi recursión cambia la derecha más alejada, y no las de la izquierda.

Probablemente sea algo pequeño, pero no puedo verlo.

  • ¿Puedo corregir la línea? _bin<C>() | _bin<D,ES...>() << 1;?
  • ¿O tengo que reenviarlo todo y darle vueltas todo después (no es agradable)?
  • ¿O alguna otra forma en que no pueda ver?

Actualizar: No pude doblar la recursión al revés, pero descubrí sizeof.... Funciona, pero no perfecto. ¿Hay otra manera?

template<char C, char D, char... ES>
int _bin() {
    return   _bin<C>() << (sizeof...(ES)+1) | _bin<D,ES...>() ;
}
¿Fue útil?

Solución

En cualquier paso de la recursión, ya conoces el rango del dígito más izquierdo.

template<char C> int _bin();
template<>       int _bin<'1'>() { return 1; }
template<>       int _bin<'0'>() { return 0; }

template<char C, char D, char... ES>
int _bin() {
    return _bin<C>() << (1 + sizeof...(ES)) | _bin<D,ES...>();
}

Otros consejos

Los paquetes de parámetros son relativamente inflexibles, y generalmente no escribe algoritmos directamente en ellos. Las plantillas de funciones variádicas son buenas para el reenvío, pero lo empacaría en un más manejable tuple antes de tratar de manipularlo.

Usando un simple binary_string_value metafunción donde el lugar de 1 viene primero y un genérico tuple_reverse metafunción, el patrón sería

template< char ... digit_pack >
constexpr unsigned long long _bin() {
    typedef std::tuple< std::integral_constant< digit_pack - '0' > ... > digit_tuple;
    return binary_string_value< typename tuple_reverse< digit_tuple >::type >::value;
}

Una posibilidad sería usar un acumulador:

template <char C>
int _binchar();
template<>
int _binchar<'0'>() { return 0; }
template<>
int _binchar<'1'>() { return 1; }

template<char C>
int _bin(int acc=0) {
   return (acc*2 + _binchar<C>());
}
template<char C, char D, char... ES>
int _bin(int acc=0) {
   return _bin<D, ES...>(acc*2 + _binchar<C>());
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top