Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP.doc
Скачиваний:
7
Добавлен:
25.04.2019
Размер:
1.34 Mб
Скачать

5.4. Специализация шаблонов

Специализация шаблона классов – это механизм, в какой-то мере противоположный самому механизму шаблонов. Действительно, цель введения шаблона – построить обобщенный вариант класса, функции или компонента. Цель специализации – определение частного случая для заданного шаблона. Специализация необходима тогда, когда определение класса (функции, компонента), инстанцируемого от шаблона, отличается от общего случая, задаваемого этим шаблоном. Например, свойства класса векторов CVector<bool>, вполне вероятно, будут отличны от свойств классов CVector<double> и CVector<int>. Например, CVector<bool> может инкапсулировать поразрядные логические операции И, ИЛИ, НЕ и исключающее ИЛИ. Подобные операции вряд ли имеют смысл для классов CVector<double> и CVector<int>. Исходя из этого, после определения шаблона CVector<T> целесообразно дать специализацию CVector<bool>, в которой, в свою очередь, ввести иное определение поведения векторов.

Для специализации23 шаблонного класса используется заголовок вида template< >, за которым следует определение класса для заданных аргументов шаблона. Специализация возможна лишь после того, как определен или, по крайней мере, объявлен сам шаблон, но до того, как осуществляется инстанцирование шаблона для аргументов специализации. Формат специализации шаблонного класса таков:

template<> class_key template-id class_declaration

где template-id представляет собой полное имя шаблонного класса для аргументов специализации: class_template_id <class_template_argument_list>.

Пример

template<class T> class CStream; // описание шаблона потоков

...

template<> class CStream<char> { /* ... */ }; // специализация для char

После такой специализации класс CStream<char> будет использован для представления потоков символов char; для потоков других типов будут использоваться классы, непосредственно (явно либо неявно) инстанцируемые от шаблона.

Приведенный ниже пример показывает более детально, как определить специализацию шаблона CVector, представляющего векторы, для компонент типа bool.

template <class T> class СVector // определение шаблона

{

T * __data; // данные вектора

int __size; // длина вектора

public:

explicit СVector(int); // конструктор

CVector(const CVector<T> &); // копирующий конструктор

~CVector( ) { delete[] __data; } // деструктор

T& Item (int i) { return __data[i]; } // получение i–го элемента

...

};

template <> class СVector<bool> // специализация

{

bool * __data; // данные

int __size; // размер

public:

explicit CVector(int); // конструктор

CVector(const CVector<bool> &); // копирующий конструктор

~CVector( ) { delete[] __data; } // деструктор

bool Item (int i) { return __data[i]; } // получение элемента

CVector<bool> NOT(void) const; // поразрядное отрицание

CVector<bool> AND(const CVector<bool> &) const; // поразрядное И

...

};

// внешнее определение функции

CVector<bool> CVector<bool>::NOT(void) const

{

CVector<bool> Result(*this);

for(int i = 0; i < __size; i++)

Result.__data[i] = !Result.__data[i];

return Result;

}

...

Специализация шаблона может быть полной или частичной. Приведенный выше пример – полная специализация. При частичной специализации, в отличие от полной, сохраняется «элемент» обобщения; иными словами, частичная специализация – это то же шаблон. Отличие частичной специализации от полной по формату касается только имени: в частичной специализации именем является полный идентификатор шаблона, а в полной – обычный идентификатор. Ниже даны примеры частичных специализаций шаблона классов:

// исходный шаблон

template <class T1, class T2, int I> class A { /* ... */ };

// частичная специализация 1

template <class T1, class T2, int I> class A<T1*,T2,I> { /* ... */ };

// частичная специализация 2

template <class T, int I> class A<T*,T,I> { /* ... */ };

// частичная специализация 3

template <class T> class A<int,T*,5> { /* ... */ };

Специализация (как полная, так и частичная) допустима не только для шаблонных классов в целом, но и для их отдельных компонент: например, статических данных, функций, шаблонов компонентных функций и вложенных шаблонов классов. Формат полной специализации для компонентной функции следующий:

template<>

value_type class_template_id<class_template_argument_list>

::function_id(function_parameter_list) { statements }

Пример

template <class T> class OneClass { // определение шаблона

public:

void f(const T &);

...

};

// специализация компонентной функции

template <> void OneClass<AnotherClass>::f(const AnotherClass & o) { }

После такой специализации функция f класса OneClass будет вести себя иным способом, если аргументом шаблона будет класс AnotherClass. При других типах аргумента поведение функции будет определяться ее обобщенным внешним определением.

Формат полной специализации шаблона компонентных функций имеет следующий вид:

template<> template<>

value_type class_template_id<class_template_argument_list>

::function_template_id<function_template_argument_list>

(function_parameter_list) { statements }

Ниже представлены еще несколько примеров полной и частичной специализации.

Пример

template<class T> struct A { // исходный шаблон

void f(T &);

void h(const T *);

template<class X> void g(const T &, X *);

};

// полная специализация компонентной функции

template<> void A<int>::f(int & ri) { /* ... */ }

// определение компонентного шаблона

template<class T> template<class X>

void A<T>::g(const T & crt, X * px) { /* ... */ }

// частичная специализация компонентного шаблона

template<> template<class X>

void A<double>::g(const double & crd, X * px) { /* ... */ }

// полная специализация компонентного шаблона

template<> template<>

void A<double>::g<int>(const double & crd, int * pi) { /* ... */ }

template<> template<>

void A<double>::g(const double & crd, char * pi) { /* ... */ }

// неявно выводится A<double>::g<char>

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]