Search code examples
c++templatesvariadic-templates

Reverse order of varidic template arguments while constructing a map key


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.


Solution

  • 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;
    }
    

    Demo