c ++ 0x: Modèle technique VARIADIC
-
27-10-2019 - |
Question
Je me préparais pour la défintion de littéraux définis par l'utilisateur avec VARIADIC modèle
template<...>
unsigned operator "" _binary();
unsigned thirteen = 1101_binary;
GCC 4.7.0 ne supporte pas operator ""
encore, mais je peux simuler cela avec une simple fonction jusque-là.
Hélas, mon récursion est le mauvais sens. Je ne peux pas penser à une façon agréable que je ne déplace pas les valeurs les plus à droite, mais l'extrême gauche :
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!
}
qui est bien sûr pas tout à fait raison:
int val13 = _bin<'1','1','0','1'>(); // <-- gives 10
parce que mes récursion déplace le plus à droite « 1 de plus éloignés, et non pas les plus à gauche ceux.
Il est sans doute que je petite chose, mais je ne peux pas le voir.
- Puis-je corriger la ligne
_bin<C>() | _bin<D,ES...>() << 1;
? - Ou dois-je avant tout et tourner autour de tout par la suite (pas bien)?
- Ou toute autre manière que je ne vois pas?
Mise à jour : Je ne pouvais pas plier la récursion l'inverse, mais j'ai découvert sizeof...
. Fonctionne, mais pas parfait. Y at-il une autre façon?
template<char C, char D, char... ES>
int _bin() {
return _bin<C>() << (sizeof...(ES)+1) | _bin<D,ES...>() ;
}
La solution
A une étape de la récursion vous connaissez déjà le rang du premier chiffre à gauche.
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...>();
}
Autres conseils
paquets de paramètres sont relativement rigides, et vous n'écrivent généralement pas des algorithmes directement en eux. modèles de fonction variadique sont bons pour le transfert, mais j'obtiendrais qui a emballé dans un tuple
plus facile à gérer avant d'essayer de le manipuler.
Utilisation simple binary_string_value
métafonction où la place du 1 vient en premier, et un tuple_reverse
générique métafonction, le motif serait
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;
}
Une possibilité serait d'utiliser un accumulateur:
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>());
}