c++0x: Variadic Template technique
I am preparing myself for the defintion of user-defined literals with a Variadic Template
template<...>
unsigned operator "" _binary();
unsigned thirteen = 1101_binary;
GCC 4.7.0 does not support operator ""
yet, but I can simulate this with a simple function until then.
Alas, my recursion is the wrong way around. I can not think of a nice way how I do not shift the rightmost values, but the leftmost:
template<char C> int _bin();
template<> 开发者_Go百科 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!
}
which of course is not quite right:
int val13 = _bin<'1','1','0','1'>(); // <-- gives 10
because my recursion shifts the rightmost '1's farthest, and not the leftmost ones.
It is probably I tiny thing, but I just can not see it.
- Can I correct the line
_bin<C>() | _bin<D,ES...>() << 1;
? - Or do I have to forward everything and turn it around everything afterwards (not nice)?
- Or any other way that I can not see?
Update: I could not fold the recursion the other way around, but I discovered sizeof...
. Works, but not perfect. Is there another way?
template<char C, char D, char... ES>
int _bin() {
return _bin<C>() << (sizeof...(ES)+1) | _bin<D,ES...>() ;
}
At any one step of the recursion you already know the rank of the leftmost digit.
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...>();
}
Parameter packs are relatively inflexible, and you don't usually write algorithms directly in them. Variadic function templates are good for forwarding, but I'd get that packed into a more manageable tuple
before trying to manipulate it.
Using a simple binary_string_value
metafunction where the 1's place comes first, and a generic tuple_reverse
metafunction, the pattern would be
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;
}
One possibility would be using an accumulator:
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>());
}
精彩评论