1. Class-Template Member Functions
The definition of a member function of a class template has the following form:
- It must start with the keyword template followed by the template parameter list for the class.
- It must indicate the class of which it is a member.
- The class name must include its template parameters.
template <class T> ret-type Queue<T>::member-name
template <class Type>
void Queue<Type>::copy_elems(const Queue &orig)
{
for (QueueItem<Type> *pt = orig.head; pt; pt = pt->next)
push(pt->item);
}
Member functions of class templates are themselves function templates. Like any other function template, a member function of a class template is used to generate instantiations of that member. Unlike other function templates, the compiler does not perform template-argument deduction when instantiating class template member functions. Instead, the template parameters of a class template member function are determined by the type of the object on which the call is made. For example, when we call the push member of an object of type Queuevoid Queue<int>::push(const int &val)
.Queue<int> qi; // instantiates class Queue<int>
short s = 42;
int i = 42;
// ok: s converted to int and passed to push
qi.push(s); // instantiates Queue<int>::push(const int&)
qi.push(i); // uses Queue<int>::push(const int&)
f(s); // instantiates f(const short&)
f(i); // instantiates f(const int&)
Member functions of a class template are instantiated only for functions that are used by the program. If a function is never used, then that member function is never instantiated
. This behavior implies that types used to instantiate a template need to meet only the requirements of the operations that are actually used. When we define an object of a template type, that definition causes the class template to be instantiated. Defining an object also instantiates whichever constructor was used to initialize the object, along with any members called by that constructor:// instantiates Queue<string> class and Queue<string>::Queue()
Queue<string> qs;
qs.push("hello"); // instantiates Queue<string>::push
template <class Type> void Queue<Type>::push(const Type &val)
{
// allocate a new QueueItem object
QueueItem<Type> *pt = new QueueItem<Type>(val);
// put item onto existing queue
if (empty())
head = tail = pt; // the queue now has only one element
else {
tail->next = pt; // add new element to end of the queue
tail = pt;
}
}
in turn instantiates the companion QueueItem
2. Template Arguments for Nontype Parameters
template <int hi, int wid> |
Nontype template arguments must be compile-time constant expressions.
3. Friend Declarations in Class Templates
(1) A friend declaration for an ordinary nontemplate class or function, which grants friendship to the specific named class or function.template <class Type> class Bar {
// grants access to ordinary, nontemplate class and function
friend class FooBar;
friend void fcn();
// ...
};
(2) A friend declaration for a class template or function template, which grants access to all instances of the friend.template <class Type> class Bar {
// grants access to Foo1 or templ_fcn1 parameterized by any type
template <class T> friend class Foo1;
template <class T> friend void templ_fcn1(const T&);
// ...
};
(3) A friend declaration that grants access only to a specific instance of a class or function template.template <class T> class Foo2;
template <class T> void templ_fcn2(const T&);
template <class Type> class Bar {
// grants access to a single specific instance parameterized by char*
friend class Foo2<char*>;
friend void templ_fcn2<char*>(char* const &);
// ...
};
More common are friend declarations of the following form:template <class T> class Foo3;
template <class T> void templ_fcn3(const T&);
template <class Type> class Bar {
// each instantiation of Bar grants access to the
// version of Foo3 or templ_fcn3 instantiated with the same type
friend class Foo3<Type>;
friend void templ_fcn3<Type>(const Type&);
// ...
};
4. Declaration Dependencies
When we grant access to all instances of a given template, there need not be a declaration for that class or function template in scope. Essentially, the compiler treats the friend declaration as a declaration of the class or function as well. When we want to restrict friendship to a specific instantiation, then the class or function must have been declared before it can be used in a friend declaration:template <class T> class A;
template <class T> class B {
public:
friend class A<T>; // ok: A is known to be a template
friend class C; // ok: C must be an ordinary, nontemplate class
template <class S> friend class D; // ok: D is a template
friend class E<T>; // error: E wasn't declared as a template
friend class F<int>; // error: F wasn't declared as a template
};
5. Making a Function Template a Friend
// function template declaration must precede friend declaration in QueueItem |