Может ли определение некой функции как специализации шаблона или как независимой, не шаблонной функции повлиять на подбор функций? Предположим, например, что имеется определение двух версий шаблонной функции compare(): той, что получает параметры как ссылки на массив, и другой, которая получает тип const T&. Факт наличия специализации для символьных указателей никак не влияет на подбор функции:

compare("hi", "mom")

Когда функция compare() вызывается для строкового литерала, оба шаблона функции оказываются подходящими и обеспечивают одинаково хорошее (т.е. точное) соответствие вызову. Однако версия с параметрами символьного массива более специализирована (см. раздел 16.3), она и выбирается для этого вызова.

Если бы была определена версия функции compare(), получающая указатели на символы, как простая, не шаблонная функция (а не как специализация шаблона), то этот вызов разрешится по-другому. В данном случае было бы три подходящих функции: эти два шаблона и не шаблонная версия указателя на символ. Все три одинаково хорошо подходят для этого вызова. Как уже упоминалось, когда нешаблонная функция обеспечивает одинаково хорошее соответствие с шаблонной, выбирается нешаблонная функция (см. раздел 16.3).

Ключевая концепция. Обычные правила области видимости относятся и к специализации

Чтобы специализировать шаблон, объявление его оригинала должно быть в области видимости. Кроме того, объявление специализации должно быть в области видимости перед любым кодом, использующим экземпляр шаблона.

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

Использование специализации и экземпляра первоначального шаблона с тем же набором аргументов шаблона является ошибкой. Но компилятор вряд ли обнаружит эту ошибку.

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

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

Кроме специализации шаблонов функций, вполне можно также специализировать шаблоны классов. В качестве примера определим специализацию библиотечного шаблона hash, который можно использовать для хранения объектов класса Sales_data в неупорядоченном контейнере. По умолчанию неупорядоченные контейнеры используют для организации своих элементов класс hash (см. раздел 11.4). Чтобы использовать его с собственным типом данных, следует определить специализацию шаблона hash. Специализированный класс hash должен определять следующее.

• Перегруженный оператор вызова (см. раздел 14.8), возвращающий тип size_t и получающий объект типа ключа контейнера.

• Два члена-типа result_type и argument_type, соответствующие типу возвращаемого значения и типу аргумента оператора вызова.

• Стандартный конструктор и оператор присвоения копии, которые могут быть определены неявно (см. раздел 13.1.2).

Единственное осложнение в определении этой специализации класса hash состоит в том, что специализация шаблона должна быть в том же пространстве имен, в котором определяется первоначальный шаблон. Более подробная информация о пространствах имен приведена в разделе 18.2, а пока достаточно знать, что к пространству имен можно добавлять члены. Для этого следует сначала открыть пространство имен:

// открыть пространство имен std, чтобы можно было специализировать

// класс std::hash

namespace std {

} // закрыть пространство имен std; обратите внимание: никакой точки с

  // запятой после закрывающей фигурной скобки

Любые определения, расположенные между открывающей и закрывающей фигурными скобками, будут частью пространства имен std.

Следующий код определяет специализацию класса hash для класса Sales_data:

Перейти на страницу:

Похожие книги