ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.12.2020
Просмотров: 4320
Скачиваний: 28
Часть II. Язык программирования С++
246
Листинг 18.5. Приведение производного класса к базовому классу
при явной конкретизации шаблона функции
#include "xchange.h"
#include <iostream>
using namespace std;
struct Base
{
int n;
};
struct Derived: Base {};
int main()
{
Base b;
Derived d;
b.n = 10;
d.n = 20;
xchange<Base>(b, d);
cout << b.n << ' ' << d.n << endl; // печатает: 20 10
return 0;
}
Способность компилятора генерировать из шаблона функции оп-
ределения различных функций в соответствии с аргументами-
типами шаблона называется
параметрическим
(parametric)
поли-
морфизмом
.
18.3. Вывод аргументов
шаблона функции
Определение типов аргументов шаблона при его неявной конкре-
тизации называется
выводом
или
дедукцией
(deduction) аргумен-
тов шаблона. Вывод аргументов шаблона заключается в сравне-
нии типов аргументов функции с параметрами-типами шаблона.
Глава 18. Шаблоны функций
247
При выводе аргументов шаблона тип значения, возвращаемого
шаблонной функцией, не принимается во внимание. При выводе
аргументов шаблона могут выполняться только следующие пре-
образования аргументов функции:
преобразования L-value:
из L-value в R-value;
из типа массива в указатель на тип элементов массива;
из типа функции в указатель на функцию;
добавление квалификаторов доступа
const
и
volatile
;
преобразования производного класса к базовому классу, если
параметром шаблона является шаблон класса.
Например, в листинге 18.6 при вызове шаблонной функции
min
тип массива
int[3]
приводится к типу указателя
int*
. Предпола-
гается, что определение шаблона функции
min
хранится в заголо-
вочном файле min.h, текст которого представлен в листинге 18.2.
Листинг 18.6. Приведение типа массива к типу указателя
#include "min.h"
#include <iostream>
using namespace std;
int main()
{
int a[3] = {3, 1, 2};
int n = min(a, 3); // приведение типа массива к указателю
cout << n << endl; // печатает 1
return 0;
}
Заметим, что ограничения на допустимые преобразования отно-
сятся только к тем аргументам функции, которые участвуют в
выводе аргументов шаблона. Для остальных аргументов функции
возможно обычное приведение типов, которое используется при
вызове функций.
Часть II. Язык программирования С++
248
Если аргумент шаблона можно вывести более чем из одного ар-
гумента функции, то в результате все эти выводы должны дать
один и тот же тип аргумента шаблона. Например, следующий вы-
зов шаблонной функции
xchange
вызовет ошибку компиляции:
int n = 1;
short m = 2;
xchange(n, m); // ошибка: неоднозначный параметр шаблона
Очевидно, что если параметром шаблона функции является не
тип, то этот параметр должен быть указан явно при вызове шаб-
лонной функции. Однако можно опустить параметры-типы шаб-
лона, которые выводятся из вызова функции, при условии, что
все эти параметры следуют после параметров, которые определе-
ны явно.
Например, в листинге 18.7 приведен пример неявной конкретиза-
ции шаблона функции, который содержит в качестве параметра
не тип. Предполагается, что определение шаблона функции
min
хранится в заголовочном файле min.h, текст которого приведен
в листинге 18.3.
Листинг 18.7. Неявная конкретизация шаблона функции
с параметром не типом
#include "min.h"
#include <iostream>
using namespace std;
int main()
{
int a[3] = {3, 1, 2};
int m = min<3>(a); // неявная конкретизация шаблона
cout << m << endl; // печатает 1
return 0;
}
Глава 18. Шаблоны функций
249
18.4. Явная специализация
шаблона функции
Явной специализацией
шаблона функции называется определение
шаблона функции для конкретных значений параметров этого
шаблона. Явная специализация шаблона функции имеет следую-
щий синтаксис:
template<>
имя_функции<список_аргументов_шаблона>(параметры_функции)
блок_функции
Здесь
имя_функции
задает имя шаблона функции, а
список_
аргументов_шаблона
содержит аргументы, для которых выполня-
ется явная специализация этого шаблона функции.
Явная специализация шаблона функции используется в двух слу-
чаях:
какой-то тип данных не может быть параметром шаблона
функции в силу невозможности такой реализации шаблона,
которая была бы совместима с другими типами данных;
специальная реализация шаблона функции для какого-то типа
данных более эффективна, чем общая реализация шаблона.
Например, рассмотрим шаблон функции:
template <class T> T max(T t1, T t2)
{
return t1 > t2 ? t1 : t2;
}
Так как общая реализация этого шаблона некорректна для строк,
то для них пишут специальную реализацию шаблона. В этом слу-
чае параметры шаблона не указываются, а после имени функции
в угловых скобках записываются аргументы шаблона для его яв-
ной специализации.
template <> char* max<char*>(char* s1, char* s2)
{
return strcmp(s1, s2) > 0 ? s1 : s2;
}
Часть II. Язык программирования С++
250
Так как в нашем случае аргументы шаблона могут быть неявно
выведены из аргументов функции, то можно специализацию
шаблона написать так:
template <> char* max<>(char* s1, char* s2)
{
return strcmp(s1, s2) > 0 ? s1 : s2;
}
или так:
template <> char* max(char* s1, char* s2)
{
return strcmp(s1, s2) > 0 ? s1 : s2;
}
А т. к. в нашем случае шаблон не содержит дополнительных па-
раметров, то явную специализацию шаблона можно заменить
нешаблонной функцией, которая никак не связана с шаблоном и
не является его явной специализацией:
char* max(char* s1, char* s2)
{
return strcmp(s1, s2) > 0 ? s1 : s2;
}
18.5. Модели компиляции шаблонов
В языке программирования C++ поддерживаются две модели
компиляции шаблонов:
модель компиляции с включением;
модель компиляции с разделением.
В модели компиляции с включением определение шаблона нуж-
но включать в каждый файл, в котором этот шаблон конкретизи-
руется. Обычно, в этом случае определение шаблона помещается
в заголовочный файл. Затем этот заголовочный файл включается
директивой
#include
в каждый исходный файл, в котором ис-
пользуется шаблон Такая компиляция шаблонов напоминает
компиляцию
inline
функций. Шаблон функции конкретизирует-