Файл: Pobegaylo_A._C_Cplus_dlya_studenta.pdf

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

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

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

Добавлен: 13.12.2020

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

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

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

Глава 18. Шаблоны функций 

251 

ся только один раз, но где и когда это происходит — решает ком-
пилятор. 
В модели компиляции с включением программист может и 

явно

 

определить момент 

конкретизации

  шаблона  функции.  Для  этого 

используется ключевое слово 

template

, после которого идет объ-

явление  шаблона  функции,  в  котором  явно  указаны  аргументы 
шаблона и параметры функции. Естественно, что явная конкрети-
зация шаблона функции выполняется в исходном файле. 
В  листингах  18.8  и  18.9  приведен  пример  явной  конкретизации 
шаблонной функции 

xchange

. Заметим, что в этих листингах при-

ведены два исходных файла, принадлежащих одному проекту. 

Листинг 18.8. Исходный файл с явной конкретизацией  
шаблона функции 

template <class T> inline void xchange(T &a, T &b) 

  T tmp = a; 
  a = b; 
  b = tmp; 

// явные конкретизации шаблона функции xchange 
template void xchange<int>(int &a, int &b); 
template void xchange<double>(double &a, double &b); 

Листинг 18.9. Исходный файл, использующий  
конкретизированные шаблонные функции 

#include <iostream> 
using namespace std; 
 
void xchange(int &a, int &b); 
void xchange(double &a, double &b); 
 
int main() 

  int n = 10, m = 20; 
  xchange(n, m);  // вызов шаблонной функции 
  cout << n << ' ' << m << endl;  // печатает 20 10 


background image

Часть II. Язык программирования С++ 

252 

  double a = 1.5, b = 2.5; 
  xchange(a, b);  // вызов шаблонной функции 
  cout << a << ' ' << b << endl;  // печатает 2.5 1.5 
 
  return 0; 

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

export

. В этом случае шаблон называется 

экспортируемым

.  Шаблон  функции  должен  быть  определен  как 

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

inline

 функций. 

Отметим,  что  эта  модель  компиляции  с  разделением  редко  под-
держивается  компиляторами  по  причине  сложности  ее  реали- 
зации. 

18.6. Перегрузка шаблонов функций 

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


background image

Глава 18. Шаблоны функций 

253 

Листинг 18.10. Перегрузка шаблонов функций 

#include <iostream> 
using namespace std; 
 
template <class S> S sum(S a, S b) { return a + b; } 
template <class S, class T> S sum(S a, T b) { return a + b; } 
 
int main() 

  cout << sum(1.1, 2) << endl; // конкретизация второго 
                               // шаблона функции 
//  cout << sum(1, 2) << endl; // ошибка, неоднозначный 
                               // выбор шаблона функции 
  return 0; 

В  случае,  рассмотренном  в  листинге  18.10,  лучше  оставить  вто-
рой шаблон функции 

sum

 с двумя параметрами разных типов, т. к. 

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

специализированным

,  чем 

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

  template<class T> void f(T); 
  template<class T> void f(const T); 


background image

Часть II. Язык программирования С++ 

254 

и: 

  template<class T> void g(T); 
  template<class T> void g(T*); 
  template<class T> void g(const T*); 

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

частичным упорядо-

чиванием

 перегруженных шаблонов. 

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

Листинг 18.11. Конкретизация более специализированного  
шаблона функции 

#include <iostream> 
using namespace std; 
// шаблон функции для вычисления суммы двух чисел 
template <class T> T sum(T m, int n) { return m + n; } 
// шаблон функции для вычисления суммы элементов массива 
template <class T> T sum(T* a, int size) 

  T s = 0; 
  for (int i = 0; i < size; ++i) 
    s += a[i]; 
  return s; 

 
int main() 

  cout << sum(1, 2) << endl;  // печатает 3 
  int a[] = {1, 2, 3}; 
  cout << sum(a, 3) << endl;  // печатает 6 
 
  return 0; 

В  случае 

sum(a,  3)

  конкретизируется  шаблон  функции  для  вы-

числения суммы элементов массива, т. к. он более специализиро-


background image

Глава 18. Шаблоны функций 

255 

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

18.7. Шаблоны функций  

как члены класса 

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

Листинг 18.12. Шаблон функции как член класса 

#include <iostream> 
using namespace std; 
 
class Demo 

public: 
  template <class T> T foo(T &t) { return t; } 
}; 
 
int main() 

  Demo d; 
  cout << d.foo(10) << endl;  // печатает 10 
 
  return 0; 


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