Professional C__ - Marc Gregoire [357]
template You can instantiate the MyVariadicTemplate with any number of types. For example: MyVariadicTemplate MyVariadicTemplate The MyVariadicTemplate can even be instantiated with zero template arguments: MyVariadicTemplate<> temp3; To avoid instantiating a variadic template with zero template arguments, you can write your template as follows: template class MyVariadicTemplate { } With this new definition, trying to instantiate MyVariadicTemplate with zero template arguments will result in a compiler error: error: wrong number of template arguments (0, should be 1 or more) It is not possible to directly iterate over the different arguments given to a variadic template. The only way you can do this is with the aid of template recursion. The following sections show two examples on how to use variadic templates. Type-Safe Variable-Length Argument Lists Variadic templates allow you to create type-safe variable-length argument lists. The following example defines a function called processValues() that uses this feature to allowing it to accept a variable number of arguments with different types in a type-safe way. The function processValues() will process each value in the variable-length argument list and will execute a function called handleValue() for each single argument. This means that you have to write a handleValue() function for each type that you want to handle; int, double and string in the following example: void handleValue(int value) { cout << "Integer: " << value << endl; } void handleValue(double value) { cout << "Double: " << value << endl; } void handleValue(const char* value) { cout << "String: " << value << endl; } template void processValues(T arg) // Base case { handleValue(arg); } template void processValues(T1 arg1, Tn... args) { processValues(arg1); processValues(args...); } Code snippet from VarArgs\VarArgsWithVariadicTemplates.cpp What the preceding example also demonstrates is the double use of the triple dots ... operator. This operator appears in two places. First, it is used behind typename to denote that this parameter can accept a variable number of arguments. The official name for typename... Tn is a parameter pack. The second use of the ... operator is behind args. In this case, the operator will unpack/expand the parameter pack args. Take the following line from the preceding example: processValues(args...); This line will unpack or expand the args parameter pack into its separate arguments, separated by commas, and then call the processValues() function with those expanded arguments. The template always requires at least one template parameter, T1. The act of recursively calling processValues() with args... is that on each call there will be one template parameter less. Since the implementation of the processValues() function is recursive, you need to have a way to stop the recursion. This is done by implementing a partial specialization of the processValues() template function, which accepts just a single template argument. You can test the processValues() variadic template as follows: processValues(1, 2, 3.56, "test", 1.1f); Code snippet from VarArgs\VarArgsWithVariadicTemplates.cpp The recursive calls generated by this example are: processValues(1, 2, 3.56, "test", 1.1f); processValues(1); handleValue(1); processValues(2, 3.56, "test", 1.1f); processValues(2); handleValue(2); processValues(3.56, "test", 1.1f); processValues(3.56); handleValue(3.56); processValues("test", 1.1f); processValues("test"); handleValue("test"); processValues(1.1f); handleValue(1.1f); It is important to remember that this method of variable-length argument lists is fully type-safe. The processValues() function will automatically call the correct handleValue() overload based on the actual type. Automatic