16.4.3. Forwarding Parameter Packs

Image

Under the new standard, we can use variadic templates together with forward to write functions that pass their arguments unchanged to some other function. To illustrate such functions, we’ll add an emplace_back member to our StrVec class (§ 13.5, p. 526). The emplace_back member of the library containers is a variadic member template (§ 16.1.4, p. 673) that uses its arguments to construct an element directly in space managed by the container.

Image

Our version of emplace_back for StrVec will also have to be variadic, because string has a number of constructors that differ in terms of their parameters. Because we’d like to be able to use the string move constructor, we’ll also need to preserve all the type information about the arguments passed to emplace_back.

As we’ve seen, preserving type information is a two-step process. First, to preserve type information in the arguments, we must define emplace_back’s function parameters as rvalue references to a template type parameter (§ 16.2.7, p. 693):

class StrVec {
public:
    template <class... Args> void emplace_back(Args&&...);
    // remaining members as in § 13.5 (p. 526)
};

The pattern in the expansion of the template parameter pack, &&, means that each function parameter will be an rvalue reference to its corresponding argument.

Second, we must use forward to preserve the arguments’ original types when emplace_back passes those arguments to construct16.2.7, p. 694):

template <class... Args>
inline
void StrVec::emplace_back(Args&&... args)
{
    chk_n_alloc(); // reallocates the StrVec if necessary
    alloc.construct(first_free++, std::forward<Args>(args)...);
}

The body of emplace_back calls chk_n_alloc13.5, p. 526) to ensure that there is enough room for an element and calls construct to create an element in the first_free spot. The expansion in the call to construct:

std::forward<Args>(args)...

expands both the template parameter pack, Args, and the function parameter pack, args. This pattern generates elements with the form

std::forward<Ti>(ti)

where Ti represents the type of the ith element in the template parameter pack and ti represents the ith element in the function parameter pack. For example, assuming svec is a StrVec, if we call

svec.emplace_back(10, 'c'), // adds cccccccccc as a new last element

the pattern in the call to construct will expand to

std::forward<int>(10), std::forward<char>(c)

By using forward in this call, we guarantee that if emplace_back is called with an rvalue, then construct will also get an rvalue. For example, in this call:

svec.emplace_back(s1 + s2); // uses the move constructor

the argument to emplace_back is an rvalue, which is passed to construct as

std::forward<string>(string("the end"))

The result type from forward<string> is string&&, so construct will be called with an rvalue reference. The construct function will, in turn, forward this argument to the string move constructor to build this element.


Exercises Section 16.4.3

Exercise 16.58: Write the emplace_back function for your StrVec class and for the Vec class that you wrote for the exercises in § 16.1.2 (p. 668).

Exercise 16.59: Assuming s is a string, explain svec.emplace_back(s).

Exercise 16.60: Explain how make_shared12.1.1, p. 451) works.

Exercise 16.61: Define your own version of make_shared.


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

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