Chapter 25. Templates

FAQ 25.01 What is the purpose of templates?

Templates share source code among structurally similar families of classes and functions.

Many data structures and algorithms can be defined independently of the type of data they manipulate. A template allows the separation of the type-dependent part from the type-independent part. The result is a significant amount of code sharing.

A template is like a cookie cutter: all the cookies it creates have the same basic shape, though they might be made from different kinds of dough. A class template describes how to build classes that implement the same data structure and algorithm, and a function template describes how to build functions that implement the same algorithm.

In other languages, these facilities are sometimes called parameterized types or genericity.

Prior to templates, macros were used as a means of implementing generics. But the results were so poor that templates have superceded them.

FAQ 25.02 What are the syntax and semantics for a class template?

The syntax of a class template is the keyword template, some template parameters, then something that looks a lot like a class. But semantically a class template is not a class: it is a cookie cutter to create a family of classes.

Consider a container class (see FAQ 2.15). In practice, the C++ source code for a container that holds ints is structurally very similar to the C++ source code for a container that holds strings. The resulting binary machine code is probably quite different, since, for example, copying an int requires different machine instructions than does copying a string. Trying to make the binary machine code the same might impose runtime overhead to generalize, for example, the copying operations for int and string and might also increase the complexity of the container.

Class templates give programmers another option: capturing the source code similarity without imposing extra runtime performance overhead. That is, the compiler generates special purpose code for containers of int, containers of string, and any others that are needed.

For example, if someone desired a container that acted like an array, in practice they would probably use the standard class template vector<T>. However, for illustration purposes we will create a class template Array<T> that acts like a safe array of T.

image

image

The template<class T> part indicates that T represents a yet unspecified type in the class template definition. Note that the keyword class doesn't imply that T must be a user-defined type; it might be a built-in type such as int or float.

The C++ Standard defines the term instantiated class to mean the instantiation of a class template, but we will use the term instantiation of a class template instead, since most C++ programmers think of an instantiated class as an object rather than another class. When it doesn't matter whether it is a class template or a function template, we will drop the qualifying adjective and refer to the instantiation of a template.

image

Normally the compiler creates an instantiation of a class template when the name of a class template is followed by a particular sequence of template arguments. In this case, the only template argument is a type. The compiler generates code for the instantiated template by replacing the template argument T with the type that is supplied, such as int.

FAQ 25.03 How can a template class be specialized to handle special cases?

Use explicit specialization.

Sometimes a programmer wants the compiler to bypass the class template when creating an instantiation of a class template for a particular type and use a specialized class template instead. For example, suppose that an array of bits is needed. The natural thing to do is create an Array<bool> using the template class from FAQ 25.02.

image

If the previously defined Array template were used to generate the code for this class, it would end up creating an array of bool which would, at best, be optimized to be an array of bytes. Clearly a bit array would be more space-efficient than a byte array. This more space-efficient implementation can be created by defining class Array<bool> as an explicit specialization of the class template Array. Notice how class Array<bool> uses a bit array rather than a byte array.

image

image

Array<bool> is an explicit specialization of the class template Array, and Array<bool> will be used instead of Array whenever an Array<bool> is needed.

image

Explicit specializations are often used to take advantage of special properties of the type T and achieve space and/or speed benefits that could not be achieved using the generic class template.

It is normally best to define the explicit specialization (for example, Array<bool>) in the same header that defines the template itself (for example, the same header that defines Array<T>). That way the compiler is guaranteed to see the explicit specialization before any uses of the specialization occur.

FAQ 25.04 What are the syntax and semantics for a function template?

The syntax of a function template is the keyword template, some template parameters, then something that looks a lot like a function. But semantically a function template is not a function: it is a cookie cutter to create a family of functions.

Consider a function that swaps its two integer arguments. Just as with Array in the preceding example, repeating the code for swap() for swapping float, char, string, and so on, will become tedious. A single function template is the solution.

image

Every time swap() appears with a new combination of parameter types, the compiler creates yet another instantiation of the function template. Here is an example.

image

As with class templates, a programmer can get the compiler to bypass the function template when creating a template function: the programmer simply needs to manually create a specialized template function.

FAQ 25.05 Should a template use memcpy() to copy objects of its template argument?

No.

An object should be bitwise copied only when it is known that the class of the object will forever be amenable to bitwise copy. But the class of a template argument can't be known. Here is an example.

image

image

image

If a template uses memcpy() to copy some T objects, the template must have a big, fat, juicy comment warning potential users that a class with nontrivial copy semantics might destroy the world. For example, if memcpy() were used in the example class template, and if someone created an Array<string>, it is likely that the memcpy() would create dangling references and/or wild pointers, and they would probably crash the application (see FAQ 32.01).

Finally, notice that the member functions that create T objects (that is, the constructors and the assignment operator) do not have exception specifications (see FAQ 9.04). This is because the T object's constructor may throw arbitrary exceptions, and any restrictions placed on these template member functions would be wrong for some particular type T.

FAQ 25.06 Why does the compiler complain about >> when one template is used inside another?

Maximal munch.

In the following example, a is a list of vector of int (list and vector are standard container classes; see FAQ 28.13).

image

If the declaration had been written without any spaces between the two > symbols, such as list<vector<int>>, the compiler would have interpreted the two > symbols as a single right-shift operator.

Here are the details. The compiler's tokenizer (something the compiler does to figure out what a program means) has a rule called the maximal munch rule: “Read characters out of the source file until adding one more character causes the current token to stop making sense.” For example, the keyword int is one token rather than three separate tokens, i, n, and t. Therefore, if the tokenizer encounters two > symbols together with no whitespace between them, the maximal munch combines them into one token: >>.

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

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