template void recycle (Type * t);  // #2

Suppose the program that contains those templates also contains the following code:

struct blot {int a; char b[10];};

blot ink = {25, "spots"};

...

recycle(&ink);  // address of a structure

The recycle(&ink) call matches Template #1, with Type interpreted as blot *. The recycle(&ink) function call also matches Template #2, this time with Type being ink. This combination sends two implicit instantiations, recycle(blot *) and recycle(blot *), to the viable function pool.

Of these two template functions, recycle(blot *) is considered the more specialized because it underwent fewer conversions in being generated. That is, Template #2 already explicitly said that the function argument was pointer-to-Type, so Type could be directly identified with blot. However, Template #1 had Type as the function argument, so Type had to be interpreted as pointer-to-blot. That is, in Template #2, Type was already specialized as a pointer, hence it is “more specialized.”

The rules for finding the most specialized template are called the partial ordering rules for function templates. Like explicit instantiations, they are C++98 additions to the C++ language.

A Partial Ordering Rules Example

Let’s examine a complete program that uses the partial ordering rules for identifying which template definition to use. Listing 8.14 has two template definitions for displaying the contents of an array. The first definition (Template A) assumes that the array that is passed as an argument contains the data to be displayed. The second definition (Template B) assumes that the array elements are pointers to the data to be displayed.

Listing 8.14. tempover.cpp

// tempover.cpp -- template overloading

#include

template             // template A

void ShowArray(T arr[], int n);

template             // template B

void ShowArray(T * arr[], int n);

struct debts

{

    char name[50];

    double amount;

};

int main()

{

    using namespace std;

    int things[6] = {13, 31, 103, 301, 310, 130};

    struct debts mr_E[3] =

    {

        {"Ima Wolfe", 2400.0},

        {"Ura Foxe", 1300.0},

        {"Iby Stout", 1800.0}

    };

    double * pd[3];

// set pointers to the amount members of the structures in mr_E

    for (int i = 0; i < 3; i++)

        pd[i] = &mr_E[i].amount;

    cout << "Listing Mr. E's counts of things:\n";

// things is an array of int

    ShowArray(things, 6);  // uses template A

    cout << "Listing Mr. E's debts:\n";

// pd is an array of pointers to double

    ShowArray(pd, 3);      // uses template B (more specialized)

    return 0;

}

template

void ShowArray(T arr[], int n)

{

    using namespace std;

    cout << "template A\n";

    for (int i = 0; i < n; i++)

        cout << arr[i] << ' ';

    cout << endl;

}

template

void ShowArray(T * arr[], int n)

{

    using namespace std;

    cout << "template B\n";

    for (int i = 0; i < n; i++)

        cout << *arr[i] << ' ';

    cout << endl;

}

Consider this function call:

ShowArray(things, 6);

The identifier things is the name of an array of int, so it matches the following template with T taken to be type int:

template              // template A

void ShowArray(T arr[], int n);

Next, consider this function call:

ShowArray(pd, 3);

Here, pd is the name of an array of double *. This could be matched by Template A:

template             // template A

void ShowArray(T arr[], int n);

Here, T would be taken to be type double *. In this case, the template function would display the contents of the pd array: three addresses. The function call could also be matched by Template B:

template             // template B

void ShowArray(T * arr[], int n);

In this case, T is type double, and the function displays the dereferenced elements *arr[i]—that is, the double values pointed to by the array contents. Of the two templates, Template B is the more specialized because it makes the specific assumption that the array contents are pointers, so it is the template that gets used.

Here’s the output of the program in Listing 8.14:

Listing Mr. E's counts of things:

template A

13 31 103 301 310 130

Listing Mr. E's debts:

template B

2400 1300 1800

If you remove Template B from the program, the compiler then uses Template A for listing the contents of pd, so it lists the addresses instead of the values. Try it and see.

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

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

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