Однако мы рассмотрим другое решение, связанное со специализацией шаблонов класса: вместо общих определений функций-членов min() и max() при конкретизации шаблона Queue типом LongDouble мы определим специальные экземпляры Queue::min() и Queue::max(), основанные на функции-члене compareLess() класса LongDouble.
Это можно сделать, если воспользоваться
// определения явных специализаций
template LongDouble Queue::min()
{
assert( ! is_empty() );
LongDouble min_val = front-item;
for ( QueueItem *pq = front-next; pq != 0; pq = pq-next )
if ( pq-item.compareLess( min_val ) )
min_val = pq-item;
return min_val;
}
template LongDouble QueueLongDouble ::max()
{
assert( ! is_empty() );
LongDouble max_val = front-item;
for ( QueueItem *pq = front-next; pq != 0; pq = pq-next )
if ( max_val.compareLess( pq-item ) )
max_val = pq-item;
return max_val;
}
Хотя тип класса Queue конкретизируется по шаблону, в каждом объекте этого типа используются специализированные функции-члены min() и max() - не те, что конкретизируются по обобщенным определениям этих функций в шаблоне класса Queue.
Поскольку определения явных специализаций min() и max() - это определения невстроенных функций, помещать их в заголовочный файл нельзя: они обязаны находится в файле с текстом программы. Однако явную специализацию функции можно объявить, не определяя. Например:
// объявления явных специализаций функций-членов
template LongDouble Queue LongDouble ::min();
template LongDouble QueueLongDouble ::max();
Поместив эти объявления в заголовочный файл, а соответствующие определения - в исходный, мы можем организовать код так же, как и для определений функций-членов обычного класса.
Иногда определение всего шаблона оказывается непригодным для конкретизации некоторым типом. В таком случае программист может специализировать шаблон класса целиком. Напишем полное определение класса Queue:
// QueueLD.h: определяет специализацию класса QueueLongDouble
#include "Queue.h"
template QueueLongDouble {
QueueLongDouble ();
~QueueLongDouble ();
LongDouble& remove();
void add( const LongDouble & );
bool is_empty() const;
LongDouble min();
LongDouble max();
private:
// Некоторая реализация
};
Явную специализацию шаблона класса можно определять только после того, как общий шаблон уже был объявлен (хотя и не обязательно определен). Иными словами, должно быть известно, что специализируемое имя обозначает шаблон класса. Если в приведенном примере не включить заголовочный файл Queue.h перед определением явной специализации шаблона, компилятор выдаст сообщение об ошибке, указывая, что Queue - это не имя шаблона.
Если мы определяем специализацию всего шаблона класса, то должны определить также все без исключения функции-члены и статические данные-члены. Определения членов из общего шаблона никогда не используются для создания определений членов явной специализации: множества членов этих шаблонов могут различаться. Чтобы предоставить определение явной специализации для типа класса Queue, придется определить не только функции-члены min() и max(), но и все остальные.
Если класс специализируется целиком, лексемы template помещаются только перед определением явной специализации всего шаблона:
#include "QueueLD.h"
// определяет функцию-член min()
// из специализированного шаблона класса
LongDouble QueueLongDouble::min() { }
Класс не может в одних файлах конкретизироваться из общего определения шаблона, а в других - из специализированного, если задано одно и то же множество аргументов. Например, специализацию шаблона QueueItem необходимо объявлять в каждом файле, где она используется:
// ---- File1.C ----
#include "Queue.h"