构造映射键时可变参数模板参数的逆序
Reverse order of varidic template arguments while constructing a map key
我正在使用可变参数模板为地图构造键,计算基数的数字:
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);
}
用 key(10, 1, 2, 3)
调用它给我一个十进制值 321
的键。我更愿意为密钥获取 123
,并且我找到了一个有效的解决方案:
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...);
}
不过,这个解决方案感觉像是一个 hack,因为它绕过一个引用来修复乘法的指数。是否有一种简单的可变方法,模板可以按所需顺序计算数字,即 123
?我见过反转可变参数的解决方案,但它们似乎过于复杂。
怎么样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...);
}
由于参数个数已知,最大指数已知,你可以直接用它来计算总和
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...);
}
(基本情况不变)
请注意,您实际上不应该在这里使用 std::pow
;编写一个执行整数幂运算的函数。
从 C++17 开始,我会使用折叠表达式 (op,...)
来做到这一点:
template<class B, class ... Args>
auto key(B base, Args ... args) {
std::common_type_t<Args...> res{};
( (res *= base, res += args % base), ... );
return res;
}
根据@Andrey Semashev 的评论,我找到了一个感觉更好的解决方案:
template<int n>
uint64_t exp(int base)
{
return base * exp<n - 1>(base);
}
template<>
uint64_t exp<0>(int base)
{
return 1;
}
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...) +
(uint64_t(n) % base) * exp< sizeof...(rest) >(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);
}
用 key(10, 1, 2, 3)
调用它给我一个十进制值 321
的键。我更愿意为密钥获取 123
,并且我找到了一个有效的解决方案:
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...);
}
不过,这个解决方案感觉像是一个 hack,因为它绕过一个引用来修复乘法的指数。是否有一种简单的可变方法,模板可以按所需顺序计算数字,即 123
?我见过反转可变参数的解决方案,但它们似乎过于复杂。
怎么样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...);
}
由于参数个数已知,最大指数已知,你可以直接用它来计算总和
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...);
}
(基本情况不变)
请注意,您实际上不应该在这里使用 std::pow
;编写一个执行整数幂运算的函数。
从 C++17 开始,我会使用折叠表达式 (op,...)
来做到这一点:
template<class B, class ... Args>
auto key(B base, Args ... args) {
std::common_type_t<Args...> res{};
( (res *= base, res += args % base), ... );
return res;
}
根据@Andrey Semashev 的评论,我找到了一个感觉更好的解决方案:
template<int n>
uint64_t exp(int base)
{
return base * exp<n - 1>(base);
}
template<>
uint64_t exp<0>(int base)
{
return 1;
}
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...) +
(uint64_t(n) % base) * exp< sizeof...(rest) >(base);
}