C++ Template Recursion

Since C++11, the template parameter list could accept non-fixed number of arguments, (parameter pack), which is similar to variadic arguments for function arguments. Those are usually handled with recursion.

Here come some examples of template function handling parameter pack with recursion.

Compared to func0(), func1() uses reference to pass parameters more efficiently. With sizeof...(T) to determine the parameter pack size, I tried to implement the recursion with a single function template (like func2()). It turns out impossible. If the condition checks whether the unexpanded parameter list T is empty, the single parameter func2() is required. This is because although when T is empty, the program would not go into the first bracket, the compiler still needs to generate the corresponding code but cannot instantiate a func2() without any parameter. The single parameter func2() could overload when only one parameter left in the list to give a termination to the recursion. The overloading is critical to get the single parameter function stop the recursion. Therefore, not only the template parameter list, but also the function argument list needs varying length. The func3() code is commented out because it tried to handle the parameter pack with no function argument, which will not work.

The code above shows multiple ways to instantiate template functions in the source code.

For a multi-file program, more than one source code file may include the header and use the function defined in the header. A common linking error is saying multiple definition of a function. One solution is to change the function defined in the header to be static, another approach is to make it a non-fully-specialized template function. I was wondering whether template function instantiated with the same set of parameters twice in two different files would trigger multi-definition error or not. Therefore, I defined another_func() in tempfunc2.cpp as shown above. It turns out the compiler would include the definition in both object files, but also flag those instantiated template function, so that linker knows the two function instantiation are the same and collapse them.

Credits