С++ для начинающих


         

Разрешение имен в шаблонах классов *


При обсуждении разрешения имен в шаблонах функций (см. раздел 10.9) мы уже говорили о том, что этот процесс выполняется в два шага. Так же разрешаются имена и в определениях шаблонов классов и их членов. Каждый шаг относится к разным видам имен: первый– к тем, которые имеют один и тот же смысл во всех экземплярах шаблона, а второй – к тем, которые потенциально могут иметь разный смысл в разных экземплярах. Рассмотрим несколько примеров, где используется функция-член remove() шаблона класса Queue:

// Queue.h:

#include <iostream>

#include <cstdlib>

// определение класса Queue

template <class Type>

Type Queue<Type>::remove() {

   if ( is_empty() ) {

      cerr << "remove() вызвана для пустой очереди\n";

      exit(-1);

   }

   QueueItem<Type> *pt = front;

   front = front->next;

   Type retval = pt->item;

   delete pt;

   cout << "удалено значение: ";

   cout << retval << endl;

   return retval;

}

В выражении

cout << retval << endl;

переменная retval имеет тип Type, и ее фактический тип неизвестен до конкретизации функции-члена remove(). То, какой оператор operator<<() будет выбран, зависит от фактического типа retval, подставленного вместо Type. При разных конкретизациях remove() могут вызываться разные operator<<(). Поэтому мы говорим, что выбранный оператор вывода зависит от параметра шаблона.

Однако для вызова функции exit() ситуация иная. Ее фактическим аргументом является литерал, значение которого одинаково при всех конкретизациях remove(). Поскольку при обращении к функции не используются аргументы, типы которых зависят от параметра шаблона Type, гарантируется, что всегда будет вызываться exit(), объявленная в заголовочном файле cstdlib. По той же причине в выражении

cout << "удалено значение: ";

всегда вызывается глобальный оператор

ostream& operator<<( ostream &, const char * );



Содержание  Назад  Вперед