Variadic Templates

Reading Time: 2 minutes

Variadic templates are nice where in you can actually let the compiler generate or instantiate the functions which would be used. Consider for example the following problem statement,

  • Create a function which can take any number of arguments and can generate the result based on the specified return type.

With macros we might be able to replace a call with something “expanded” but we’ll turn into another problem of how to actually deal with the variadic arguments. printf handles the variadic arguments based on the format specifier, however we don’t want to provide a format specifier or the number of variadic arguments.

Variadic templates to rescue...

#include <iostream>

template<typename R, typename Arg>
R sum(Arg arg) {
    return arg;
}

template<typename  R, typename First, typename ...Arg>
R sum(First first, Arg... args) {
    return first + sum<R>(args...);
} 

In the above code we’ve first defined a specialization where there’s only a single argument. Then we define the variadic template with an additional parameter pack of Arg.

When compiler sees the call to sum it’ll instantiate the correct sum function and the recursion will bottom out using the specialization. 

NOTE: the specialization needs to be defined earlier rather than later since the compiler needs to know what it can use, otherwise it causes compiler error due to multiple definitions of the call sum<int>(1) .

The full listing of the above example is shown below

#include <iostream>


template<typename R, typename Arg>
R sum(Arg arg) {
    return arg;
}

template<typename  R, typename First, typename ...Arg>
R sum(First first, Arg... args) {
    return first + sum<R>(args...);
}

//This is just to avoid typing and auto generate the call as a string.
//This has nothing to do with variadic templates.
#define SUM(type, ARGS...) \
    std::cout<<"Sum of "<<#ARGS<<" = "<<sum<type>(ARGS)<<"\n"

int main() {
    std::cout << "Hello, World!" << std::endl;
    SUM(int, 1, 2);
    SUM(float, 1.1, 2, 3, 4.0);
    return 0;
}
 

Thanks for reading!. If you liked it do share!

Leave a Reply