Файл: Pobegaylo_A._C_Cplus_dlya_studenta.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 13.12.2020

Просмотров: 4320

Скачиваний: 28

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

Часть 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)  аргумен-

тов  шаблона.  Вывод  аргументов  шаблона  заключается  в  сравне-
нии  типов  аргументов  функции  с  параметрами-типами  шаблона. 


background image

Глава 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; 

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


background image

Часть 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; 


background image

Глава 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; 
  } 


background image

Часть 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

  функций.  Шаблон  функции  конкретизирует-


Смотрите также файлы