16.4.1. Writing a Variadic Function Template

Image

In § 6.2.6 (p. 220) we saw that we can use an initializer_list to define a function that can take a varying number of arguments. However, the arguments must have the same type (or types that are convertible to a common type). Variadic functions are used when we know neither the number nor the types of the arguments we want to process. As an example, we’ll define a function like our earlier error_msg function, only this time we’ll allow the argument types to vary as well. We’ll start by defining a variadic function named print that will print the contents of a given list of arguments on a given stream.

Variadic functions are often recursive (§ 6.3.2, p. 227). The first call processes the first argument in the pack and calls itself on the remaining arguments. Our print function will execute this way—each call will print its second argument on the stream denoted by its first argument. To stop the recursion, we’ll also need to define a nonvariadic print function that will take a stream and an object:

// function to end the recursion and print the last element
// this function must be declared before the variadic version of print is defined
template<typename T>
ostream &print(ostream &os, const T &t)
{
    return os << t; // no separator after the last element in the pack
}
// this version of print will be called for all but the last element in the pack
template <typename T, typename... Args>
ostream &print(ostream &os, const T &t, const Args&... rest)
{
    os << t << ", ";           // print the first argument
    return print(os, rest...); // recursive call; print the other arguments
}

The first version of print stops the recursion and prints the last argument in the initial call to print. The second, variadic, version prints the argument bound to t and calls itself to print the remaining values in the function parameter pack.

The key part is the call to print inside the variadic function:

return print(os, rest...); // recursive call; print the other arguments

The variadic version of our print function takes three parameters: an ostream&, a const T&, and a parameter pack. Yet this call passes only two arguments. What happens is that the first argument in rest gets bound to t. The remaining arguments in rest form the parameter pack for the next call to print. Thus, on each call, the first argument in the pack is removed from the pack and becomes the argument bound to t. That is, given:

print(cout, i, s, 42);  // two parameters in the pack

the recursion will execute as follows:

Image

The first two calls can match only the variadic version of print because the nonvariadic version isn’t viable. These calls pass four and three arguments, respectively, and the nonvariadic print takes only two arguments.

For the last call in the recursion, print(cout, 42), both versions of print are viable. This call passes exactly two arguments, and the type of the first argument is ostream&. Thus, the nonvariadic version of print is viable.

The variadic version is also viable. Unlike an ordinary argument, a parameter pack can be empty. Hence, the variadic version of print can be instantiated with only two parameters: one for the ostream& parameter and the other for the const T& parameter.

Both functions provide an equally good match for the call. However, a nonvariadic template is more specialized than a variadic template, so the nonvariadic version is chosen for this call (§ 16.3, p. 695).


Image Warning

A declaration for the nonvariadic version of print must be in scope when the variadic version is defined. Otherwise, the variadic function will recurse indefinitely.



Exercises Section 16.4.1

Exercise 16.53: Write your own version of the print functions and test them by printing one, two, and five arguments, each of which should have different types.

Exercise 16.54: What happens if we call print on a type that doesn’t have an << operator?

Exercise 16.55: Explain how the variadic version of print would execute if we declared the nonvariadic version of print after the definition of the variadic version.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.234.150