A variadic template is a template function or class that can take a varying number of parameters. The varying parameters are known as a parameter pack. There are two kinds of parameter packs: A template parameter pack represents zero or more template parameters, and a function parameter pack represents zero or more function parameters.
We use an ellipsis to indicate that a template or function parameter represents a pack. In a template parameter list, class...
or typename...
indicates that the following parameter represents a list of zero or more types; the name of a type followed by an ellipsis represents a list of zero or more nontype parameters of the given type. In the function parameter list, a parameter whose type is a template parameter pack is a function parameter pack. For example:
// Args is a template parameter pack; rest is a function parameter pack
// Args represents zero or more template type parameters
// rest represents zero or more function parameters
template <typename T, typename... Args>
void foo(const T &t, const Args& ... rest);
declares that foo
is a variadic function that has one type parameter named T
and a template parameter pack named Args
. That pack represents zero or more additional type parameters. The function parameter list of foo
has one parameter, whose type is a const &
to whatever type T
has, and a function parameter pack named rest
. That pack represents zero or more function parameters.
As usual, the compiler deduces the template parameter types from the function’s arguments. For a variadic template, the compiler also deduces the number of parameters in the pack. For example, given these calls:
int i = 0; double d = 3.14; string s = "how now brown cow";
foo(i, s, 42, d); // three parameters in the pack
foo(s, 42, "hi"); // two parameters in the pack
foo(d, s); // one parameter in the pack
foo("hi"); // empty pack
the compiler will instantiate four different instances of foo
:
void foo(const int&, const string&, const int&, const double&);
void foo(const string&, const int&, const char(&)[3]);
void foo(const double&, const string&);
void foo(const char(&)[3]);
In each case, the type of T
is deduced from the type of the first argument. The remaining arguments (if any) provide the number of, and types for, the additional arguments to the function.