For this to be accepted, the template argument King has to be a template class whose declaration matches that of the template parameter Thing:

template

class King {...};

The Crab declaration in Listing 14.21 declares two objects:

Thing s1;

Thing s2;

The previous declaration for legs would then result in substituting King for Thing and King for Thing. However, Listing 14.21 has this declaration:

Crab nebula;

Hence, in this case, Thing is instantiated as Stack, and Thing is instantiated as Stack. In short, the template parameter Thing is replaced by whatever template type is used as a template argument in declaring a Crab object.

The Crab class declaration makes three further assumptions about the template class represented by Thing. The class should have a push() method, the class should have a pop() method, and these methods should have a particular interface. The Crab class can use any template class that matches the Thing type declaration and that has the prerequisite push() and pop() methods. This chapter happens to have one such class, the Stack template defined in stacktp.h, so the example uses that class.

Listing 14.21. tempparm.cpp

// tempparm.cpp – templates as parameters

#include

#include "stacktp.h"

template

class Crab

{

private:

    Thing s1;

    Thing s2;

public:

    Crab() {};

    // assumes the thing class has push() and pop() members

    bool push(int a, double x) { return s1.push(a) && s2.push(x); }

    bool pop(int & a, double & x){ return s1.pop(a) && s2.pop(x); }

};

int main()

{

    using std::cout;

    using std::cin;

    using std::endl;

    Crab nebula;

// Stack must match template class thing

    int ni;

    double nb;

    cout << "Enter int double pairs, such as 4 3.5 (0 0 to end):\n";

    while (cin>> ni >> nb && ni > 0 && nb > 0)

    {

        if (!nebula.push(ni, nb))

            break;

    }

    while (nebula.pop(ni, nb))

           cout << ni << ", " << nb << endl;

    cout << "Done.\n";

    return 0;

}

Here is a sample run of the program in Listing 14.21:

Enter int double pairs, such as 4 3.5 (0 0 to end):

50 22.48

25 33.87

60 19.12

0 0

60, 19.12

25, 33.87

50, 22.48

Done.

You can mix template parameters with regular parameters. For example, the Crab class declaration could start out like this:

template

class Crab

{

private:

    Thing s1;

    Thing s2;

...

Now the types to be stored in the members s1 and s2 are generic types instead of hard-coded types. This would require the declaration of nebula in the program to be changed to this:

Crab nebula; // T=Stack, U=int, V=double

The template parameter T represents a template type, and the type parameters U and V represent non-template types.

Template Classes and Friends

Template class declarations can have friends, too. You can classify friends of templates into three categories:

• Non-template friends

• Bound template friends, meaning the type of the friend is determined by the type of the class when a class is instantiated

• Unbound template friends, meaning that all specializations of the friend are friends to each specialization of the class

Let’s look at examples of each.

Non-Template Friend Functions to Template Classes

Let’s declare an ordinary function in a template class as a friend:

template

class HasFriend

{

public:

    friend void counts();     // friend to all HasFriend instantiations

    ...

};

This declaration makes the counts() function a friend to all possible instantiations of the template. For example, it would be a friend to the HasFriend class and the HasFriend class.

The counts() function is not invoked by an object (it’s a friend, not a member function), and it has no object parameters, so how does it access a HasFriend object? There are several possibilities. It could access a global object; it could access nonglobal objects by using a global pointer; it could create its own objects; and it could access static data members of a template class, which exist separately from an object.

Suppose you want to provide a template class argument to a friend function. Can you have a friend declaration like this, for example?

friend void report(HasFriend &);   // possible?

The answer is no. The reason is that there is no such thing as a HasFriend object. There are only particular specializations, such as HasFriend. To provide a template class argument, then, you have to indicate a specialization. For example, you can use this:

template

class HasFriend

{

    friend void report(HasFriend &); // bound template friend

    ...

};

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

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

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