I am using a variadic template to construct a key for a map, calculating a number to a base:
template<typename T>
uint64_t key(int base, T n)
{
return uint64_t(n) % base;
}
template<typename T, typename... Args>
uint64_t key(int base, T n, Args... rest)
{
return key(base, rest...) * base (uint64_t(n) % base);
}
Calling it with key(10, 1, 2, 3)
gives me a key with decimal value 321
. I would prefer to get 123
for the key, and I have found a solution that works:
template<typename T>
uint64_t keyHelper(int& mul, int base, T n)
{
mul = base;
return uint64_t(n) % base;
}
template<typename T, typename... Args>
uint64_t keyHelper(int& mul, int base, T n, Args... rest)
{
int mul_tmp;
uint64_t result = keyHelper(mul_tmp, base, rest...)
(uint64_t(n) % base) * mul_tmp;
mul = mul_tmp * base;
return result;
}
template<typename... Args>
uint64_t key(int base, Args... args)
{
int mul;
return keyHelper(mul, base, args...);
}
This solution feels like a hack, tho, since it passes around a reference to fix the exponent of multiplications. Is there a simple varidic way where the template calculates the number in the required order, i.e. 123
? I have seen solutions for reversing variadic arguments, and they seem overly complicated.
CodePudding user response:
Since C 17 I would use fold expression (op,...)
to do that:
template<class B, class ... Args>
auto key(B base, Args ... args) {
std::common_type_t<Args...> res{};
( (res *= base, res = args % base), ... );
return res;
}
CodePudding user response:
How about this:
template<typename T>
uint64_t key_impl(int base, unsigned int exp, T n)
{
return uint64_t(n) % base;
}
template<typename T, typename... Args>
uint64_t key_impl(int base, unsigned int exp, T n, Args... rest)
{
uint64_t res = uint64_t(n) % base;
for (unsigned int i = 0u; i < exp; i)
res *= base;
return key_impl(base, exp - 1u, rest...) res;
}
template<typename... Args>
uint64_t key(int base, Args... args)
{
return key_impl(base, sizeof...(Args) - 1u, args...);
}
CodePudding user response:
Since the number of arguments is known, the maximum exponent is known, and you can just use that to calculate the sum
template<typename T, typename... Args>
uint64_t key(int base, T n, Args... rest)
{
return (uint64_t(n) % base) * std::pow(base, sizeof...(rest))
key(base, rest...);
}
(the base case is unchanged)
Note that you shouldn't actually use std::pow
here; write a function that does integer exponentiation instead.