Using compiler-generated int swapper:

Now i, j = 20, 10.

Original arrays:

07/04/1776

07/20/1969

Swapped arrays:

07/20/1969

07/04/1776

Template Limitations

Suppose you have a template function:

template      // or template

void f(T a, T b)

{...}

Often the code makes assumptions about what operations are possible for the type. For instance, the following statement assumes that assignment is defined, and this would not be true if type T is a built-in array type:

a = b;

Similarly, the following assumes > is defined, which is not true if T is an ordinary structure:

if (a > b)

Also the > operator is defined for array names, but because array names are addresses, it compares the addresses of the arrays, which may not be what you have in mind. And the following assumes the multiplication operator is defined for type T, which is not the case if T is an array, a pointer, or a structure:

T c = a*b;

In short, it’s easy to write a template function that cannot handle certain types. On the other hand, sometimes a generalization makes sense, even if ordinary C++ syntax doesn’t allow for it. For example, it could make sense to add structures containing position coordinates, even though the + operator isn’t defined for structures. One approach is that C++ allows one to overload the + operator so that it can be used with a particular form of structure or class. Chapter 11 discusses this facility. A template that requires using the + operator then could handle a structure that had an overloaded + operator. Another approach is to provide specialized template definitions for particular types. Let’s look at that next.

Explicit Specializations

Suppose you define a structure like the following:

struct job

{

      char name[40];

      double salary;

      int floor;

};

Also suppose you want to be able to swap the contents of two such structures. The original template uses the following code to effect a swap:

temp = a;

a = b;

b = temp;

Because C++ allows you to assign one structure to another, this works fine, even if type T is a job structure. But suppose you only want to swap the salary and floor members, keeping the name members unchanged. This requires different code, but the arguments to Swap() would be the same as for the first case (references to two job structures), so you can’t use template overloading to supply the alternative code.

However, you can supply a specialized function definition, called an explicit specialization, with the required code. If the compiler finds a specialized definition that exactly matches a function call, it uses that definition without looking for templates.

The specialization mechanism has changed with the evolution of C++. We’ll look at the current form as mandated by the C++ Standard.

Third-Generation Specialization (ISO/ANSI C++ Standard)

After some youthful experimentation with other approaches, the C++98 Standard settled on this approach:

• For a given function name, you can have a non template function, a template function, and an explicit specialization template function, along with overloaded versions of all of these.

• The prototype and definition for an explicit specialization should be preceded by template <> and should mention the specialized type by name.

• A specialization overrides the regular template, and a non template function overrides both.

Here’s how prototypes for swapping type job structures would look for these three forms:

// non template function prototype

void Swap(job &, job &);

// template prototype

template

void Swap(T &, T &);

// explicit specialization for the job type

template <> void Swap(job &, job &);

As mentioned previously, if more than one of these prototypes is present, the compiler chooses the non template version over explicit specializations and template versions, and it chooses an explicit specialization over a version generated from a template. For example, in the following code, the first call to Swap() uses the general template, and the second call uses the explicit specialization, based on the job type:

...

template           // template

void Swap(T &, T &);

// explicit specialization for the job type

template <> void Swap(job &, job &);

int main()

{

    double u, v;

    ...

    Swap(u,v);  // use template

    job a, b;

    ...

    Swap(a,b);  // use void Swap(job &, job &)

}

The in Swap is optional because the function argument types indicate that this is a specialization for job. Thus, the prototype can also be written this way:

template <> void Swap(job &, job &);   // simpler form

In case you have to work with an older compiler, we’ll come back to pre-C++ Standard usage soon, but first, let’s see how explicit specializations are supposed to work.

An Example of Explicit Specialization

Перейти на страницу:

Все книги серии Developer's Library

Похожие книги