Может ли определение некой функции как специализации шаблона или как независимой, не шаблонной функции повлиять на подбор функций? Предположим, например, что имеется определение двух версий шаблонной функции 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, а пока достаточно знать, что к пространству имен можно добавлять члены. Для этого следует сначала открыть пространство имен:
//
//
namespace std {
} //
//
Любые определения, расположенные между открывающей и закрывающей фигурными скобками, будут частью пространства имен std
.
Следующий код определяет специализацию класса hash
для класса Sales_data
: