Урок №178. Явная специализация шаблона класса

  Юрий Ворон  | 

    | 

  Обновлено 17 Ноя 2018  | 

 505

 ǀ   3 

В предыдущем уроке мы говорили о том, как специализировать шаблон функции, чтобы при работе с одним типом данных была одна реализация функции, а при работе с другим типом данных – другая реализация функции. Оказывается, мы можем специализировать не только шаблоны функций, но и шаблоны классов.

Рассмотрим класс-массив, который может хранить 8 объектов:

Поскольку это шаблон класса, то он будет работать с любым типом данных:

Результат:

0
1
2
3
4
5
6
7
false
true
true
true
true
false
true
true

Хотя всё работает правильно, реализация Repository8<bool>, на самом деле, не столь эффективна, какой она может быть. Поскольку все переменные должны иметь адрес, а ЦП не может дать адрес чему-либо меньшему чем 1 байт, то размер всех переменных должен быть не менее 1 байта. Следовательно, каждая переменная типа bool занимает целый байт, хотя технически ей нужен только 1 бит для хранения значения true или false! Таким образом, переменная типа bool — это 1 бит полезной информации и 7 бит потраченного впустую места. Получается, наш класс Repository8<bool>, который имеет 8 переменных типа bool, фактически работает только с 1 байтом данных, а остальные 7 байтов тратятся вхолостую.



Выход есть — мы можем сжать 8 переменных типа bool в 1 байт, сэкономив при этом остальные 7 байтов. Однако для этого нам нужно изменить реализацию класса, заменив массив из 8 переменных типа bool (8 байтов) на 1 переменную unsigned char (1 байт). Мы могли бы, конечно, использовать для этого новый отдельный класс, но это не эффективно + программисту придется помнить, что Repository8<T> работает со всеми типами данных, кроме bool, а при работе с bool следует вызывать Repository8Bool (неважно, как вы назовете этот класс). Это лишняя работа и логика, которую можно избежать, используя явную специализацию шаблона класса.

Специализация шаблона класса

Специализация шаблона класса (или еще «явная специализация шаблона класса») позволяет специализировать шаблон класса для работы с определенным типом данных (или сразу несколькими типами данных, если несколько параметров шаблона).

Специализация шаблона класса рассматривается компилятором как полностью отдельный и независимый класс, хотя и выделяется как обычный шаблон класса. Это означает, что мы можем изменить в классе всё что угодно, включая его реализацию/методы/спецификаторы доступа и т.д.

Рассмотрим специализацию шаблона класса Repository8 для работы с типом bool:

Во-первых, начинаем с template<>. Ключевое слово template сообщает компилятору, что это шаблон, а пустые угловые скобки означают, что нет никаких параметров. А параметров нет из-за того, что мы заменяем единственный параметр шаблона (T, который отвечает за тип данных) конкретным типом данных (bool). Затем мы пишем имя класса и добавляем к нему <bool>, сообщая компилятору, что работать будем с типом bool.

Все остальные изменения — это просто детали реализации класса. Обратите внимание, вместо массива из 8 переменных типа bool (8 байтов) мы используем 1 unsigned char (1 байт). Почему так? Об этом читайте в уроке №45 о побитовых операторах и уроке №46 о битовых флагах и масках.

Теперь, при объявлении объекта класса Repository8<T>, где T не является bool, мы получим экземпляр общего шаблона класса, тогда как при объявлении объекта Repository8<bool>, мы получим экземпляр шаблона Repository8<bool>. Обратите внимание, мы не изменяли интерфейс класса, а оставили его открытым (каким он и был) — в то время как C++ дает нам возможность добавлять/изменять/удалять методы класса. Дело в том, что изменение интерфейса класса в специализациях шаблона не всегда приветствуется, так как программист может это дело забыть, а оно, в свою очередь, приведет к ошибкам.

Создадим объекты Repository8<T> и Repository8<bool>:

Как вы можете видеть, результат тот же, что и выше, где использовался общий шаблон класса Repository8:

0
1
2
3
4
5
6
7
false
true
true
true
true
false
true
true

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

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (6 оценок, среднее: 5,00 из 5)
Загрузка...

Комментариев: 3

  1. rrrrr:

    cпециализация шаблона класса не работает

    'Repository8' is not a class template

    1. Юрий Ворон Юрий Ворон:

      Потому что нужно указывать ещё и следующий код:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *