Что произойдет, если наша программа использует шаблон, определенный в пространстве имен, и мы хотим предоставить для него специализацию? (Явные специализации шаблонов рассматривались в разделе 10.6.) Допустим, мы хотим использовать шаблон min(), определенный в cplusplus_primer, для нахождения минимального значения в массиве объектов типа SmallInt. Однако мы осознаем, что имеющееся определение шаблона не вполне подходит, поскольку сравнение в нем выглядит так:
if ( array[i] min_val )
В этой инструкции два объекта класса SmallInt сравниваются с помощью оператора . Но этот оператор неприменим к объектам, если только не перегружен в классе SmallInt (мы покажем, как определять перегруженные операторы в главе 15). Предположим, что мы хотели бы определить специализацию шаблона min(), чтобы она пользовалась функцией compareLess() для сравнения двух подобных объектов. Вот ее объявление:
// функция сравнения объектов SmallInt
// возвращает true, если parm1 меньше parm2
bool compareLess( const SmallInt parm1, const SmallInt parm2 );
Как должно выглядеть определение этой функции? Чтобы ответить на этот вопрос, необходимо познакомиться с определением класса SmallInt более подробно. Данный класс позволяет определять объекты, которые хранят тот же диапазон значений, что и 8-разрядный тип unsigned char, т.е. от 0 до 255. Дополнительная функциональность состоит в том, что класс перехватывает ошибки переполнения и потери значимости. Во всем остальном он должен вести себя точно так же, как unsigned char. Определение SmallInt выглядит следующим образом:
class SmallInt {
public:
SmallInt( int ival ) : value( ival ) {}
friend bool compareLess( const SmallInt , const SmallInt );
private:
int value; // член
};
В этом классе есть один закрытый член value, в котором хранится значение объекта типа SmallInt. Класс также содержит конструктор с параметром ival:
// конструктор класса SmallInt
SmallInt( int ival ) : value( ival ) {}
Его единственное назначение – инициализировать член класса value значением ival.
Вот теперь можно ответить на ранее поставленный вопрос: как должна быть определена функция compareLess()? Она будет сравнивать члены value переданных ей аргументов типа SmallInt:
// возвращает true, если parm1 меньше parm2
bool compareLess( const SmallInt parm1, const SmallInt parm2 ) {
return parm1.value parm2.value;
}
Заметим, однако, что член value является закрытым. Как может глобальная функция обратиться к закрытому члену, не нарушив инкапсуляции класса SmallInt и не вызвав тем самым ошибку компиляции? Если вы посмотрите на определение класса SmallInt, то заметите, что глобальная функция compareLess() объявлена как дружественная (friend). Если функция объявлена таким образом, то ей доступны закрытые члены класса. (Друзья классов рассматриваются в разделе 15.2.)
Теперь мы готовы определить специализацию шаблона min(). Она следующим образом использует функцию compareLess().
// специализация min() для массива объектов SmallInt
template SmallInt minsmallInt( SmallInt* array, int size )
{
SmallInt min_val = array[0];
for (int i = 1; i size; ++i)
// при сравнении используется функция compareLess()
if ( compareLess( array[i], min_val ) )
min_val = array[i];
print( "Minimum value found: " );
print( min_val );
return min_val;
}
Где мы должны объявить эту специализацию? Предположим, что здесь:
// ---- primer.h ----
namespace cplusplus_primer {
// определение шаблона скрыто в пространстве имен
template class Type
Type min( Type* array, int size ) { /* ... */ }
}
// ---- user.h ----
class SmallInt { /* ... */ };
void print( const SmallInt );
bool compareLess( const SmallInt , const SmallInt );
// ---- user.C ----
#include primer.h
#include "user.h"