Search code examples
c++variadic-templatesvariadic-functions

Convert Variadic Template Function to many concrete functions


Is there a compiler flag or technique to force the generation of one non-variadic function for each call to a variadic function template with a unique signature?

In the following example, the compiler creates variadic templates with signatures int (int, float, double), int (float, double) and int (double).

#include <iostream>

using namespace std;

template<class IntT, class argsf>
IntT SumArgs(const argsf& firstArg)
{
    return static_cast<IntT>(firstArg);
}

template<class IntT, class argsf, class ...argst>
IntT SumArgs(const argsf& firstArg, const argst&... restArgs)
{
    return static_cast<IntT>(firstArg + SumArgs<IntT>(restArgs...));
}

int main()
{
    cout<<"Sum result: " << SumArgs<int>(1, 2.f, 3.5);
    return 0;
}

The first two remain variadic. However, in some circumstances, it might be desirable to avoid the overhead of variadic functions and instead create a unique function definition for each signature listed above. Is there a way to get compilers to do this? The alternative is to write versions of the function that explicitly use 0, 1, 2 ... n arguments for some reasonably large n and duplicate the code by hand, but ideally the compiler could do this heavy-lifting for us.


Solution

  • C++17 introduces fold expressions which are (hopefully) exactly what you are looking for:

    template <class R, class... Args>
    constexpr R SumArgs(const Args&... args)
    {
        return static_cast<R>((args + ...)); // fold expression
    }
    

    If you don't want to use variadic templates, you can use an initializer_list:

    template <class R, class T>
    constexpr R SumArgs(std::initializer_list<T> args)
    {
        return std::accumulate(args.begin(), args.end(), R{});
    }