Domanda

Mi sto preparando per la definizione di letterali definiti dall'utente con un Modello variadico

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

unsigned thirteen = 1101_binary;

GCC 4.7.0 non supporta operator "" Eppure, ma posso simularlo con una semplice funzione fino ad allora.

Ahimè, la mia ricorsione è il modo sbagliato. Non riesco a pensare a un bel modo Non spostare i valori più a destra, ma il più a sinistra:

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!
}

Quale ovviamente non è del tutto giusto:

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

Perché la mia ricorsione sposta il più a destra dell'1 più lontano, e non quella più a sinistra.

Probabilmente è una cosa piccola, ma non riesco proprio a vederlo.

  • Posso correggere la linea _bin<C>() | _bin<D,ES...>() << 1;?
  • O devo inoltrare tutto e girarlo in seguito (non è bello)?
  • O in qualsiasi altro modo in cui non riesco a vedere?

Aggiornare: Non ho potuto piegare la ricorsione al contrario, ma ho scoperto sizeof.... Funziona, ma non perfetto. C'è un altro modo?

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

Soluzione

In ogni fase della ricorsione conosci già il grado della cifra più a sinistra.

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...>();
}

Altri suggerimenti

I pacchetti di parametri sono relativamente inflessibili e di solito non scrivi algoritmi direttamente in essi. I modelli di funzionalità variadici sono utili per l'inoltro, ma lo farei impacchettare in un più gestibile tuple Prima di provare a manipolarlo.

Usando un semplice binary_string_value metafunzione dove il posto dell'1 viene prima e generico tuple_reverse metafunzione, il modello sarebbe

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 possibilità sarebbe usare un accumulatore:

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>());
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top