Упражнение 16.59. С учетом того, что s имеет тип string, объясните вызов svec.emplace_back(s).

Упражнение 16.60. Объясните, как работает функция make_shared() (см. раздел 12.1.1).

Упражнение 16.61. Определите собственную версию функции make_shared().

<p><image l:href="#books.png"/>16.5. Специализация шаблона</p>

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

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

// первая версия; может сравнить любые два типа

template int compare(const T&, const T&);

// вторая версия, для обработки строковых литералов

template

int compare(const char (&)[N], const char (&)[M]);

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

const char *p1 = "hi", *p2 = "mom";

compare(p1, p2);      // вызывает первый шаблон

compare("hi", "mom"); // вызывает шаблон с двумя параметрами значения

Нет никакого способа преобразовать указатель в ссылку на массив, поэтому вторая версия функции compare() не подходит для передачи указателей p1 и p2 как аргументов.

Для обработки символьных указателей (в отличие от массивов) можно определить специализацию шаблона (template specialization) для первой версии функции compare(). Специализация — это отдельное определение шаблона, в котором определяется один или несколько параметров шаблона для получения специфического типа.

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

При специализации шаблона функции следует предоставить аргументы для каждого параметра первоначального шаблона. Для указания специализации шаблона используется ключевое слово template, сопровождаемое парой пустых угловых скобок (<>). Пустые скобки означают, что аргументы будут предоставлены для всех параметров первоначального шаблона:

// специальная версия compare() для работы с указателями на символьные

// массивы

template <>

int compare(const char* const &p1, const char* const &p2) {

 return strcmp(p1, p2);

}

Трудная для понимания часть этой специализации относится к типам параметра функции. При определении специализации типы параметров функции должны совпадать с соответствующими типами ранее объявленного шаблона:

template int compare(const T&, const T&);

В этой специализации параметры функции являются ссылками на константные типы. Подобно псевдонимам типа, взаимодействие между типами параметра шаблона, указателями и константами может удивить (см. раздел 2.5.1).

Необходимо определить специализацию шаблона этой функции с типом const char* для параметра Т. Функция потребует ссылки на константную версию этого типа. Константная версия типа указателя — это константный указатель, а не указатель на константу (см. раздел 2.4.2). В данной специализации следует использовать тип const char* const &, являющийся ссылкой на константный указатель на константный символ.

Перегрузка функций или специализация шаблона

При определении специализации шаблона функции разработчик, по существу, выполняет задачу компилятора. Таким образом, определение предоставляется для использования специфического экземпляра первоначального шаблона. Важно понимать, что специализация — это создание экземпляра функции; а не перегрузка ее экземпляра.

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

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

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