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
Thing
The previous declaration for legs would then result in substituting King
Crab
Hence, in this case, Thing
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 Thing>
class Crab
{
private:
Thing
Thing
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
// Stack must match template
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 Thing, typename U, typename V>
class Crab
{
private:
Thing s1;
Thing
...
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
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
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
template
class HasFriend
{
friend void report(HasFriend
...
};