У вас вопросы?
У нас ответы:) SamZan.net

Шаблоны функций Объявления и описания функцийшаблонов начинаются с ключевого слова templte англ

Работа добавлена на сайт samzan.net: 2016-03-30

Поможем написать учебную работу

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

Предоплата всего

от 25%

Подписываем

договор

Выберите тип работы:

Скидка 25% при заказе до 4.3.2025

Рубанчик В. Б.

Лабораторная №4

Шаблоны функций. Шаблоны классов (параметризованные типы).

6/6

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

Объявления и описания функций-шаблонов начинаются с ключевого слова template (англ. шаблон), за которым в угловых скобках записывается список формальных параметров шаблона (формальных параметров не функции, а шаблона!), которые называют параметрами настройки шаблона. Этот список должен содержать по крайней мере один элемент (т.е. не может быть пустым).

Параметры настройки шаблона при генерации (с помощью шаблона) конкретной функции принимают "значения" описателей базовых или пользовательских типов данных.

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

Параметры настройки шаблона в списке параметров должны различаться по именам.

Пример.

Функция swap обменивает значениями две переменные:

template <class T>                                           или

void swap(T &x, T &y)

{ T z;

z=x; x=y; y=z;}

template <class T>

void swap(T *x, T *y)

{ T z;

z=*x; *x=*y; *y=z;}

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

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

Каждый включенный в список параметр настройки шаблона должен появиться в списке аргументов функции хотя бы один раз. Это требование связано с механизмом конкретизации этих "типовых" переменных. Использование параметра только для описания типа возвращаемого значения недостаточно.

Для шаблонной функции может быть объявлен прототип, причем имена параметров настройки шаблона в прототипе и в описании функции могут различаться (как и в случае обычных аргументов функции). Однако объявление шаблона (прототип) может быть только глобальным, то есть, размещено на внешнем уровне.

//прототип

template <class T> T f(T x);

//описание функции

template <class U> U f(U x)

{...}

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

int T;

template <class T> T f(T x) {

T  a;        // "локальное" T

::T=1;       // "глобальное" T }

Функция-шаблон может быть описана как статическая и подставляемая. Спецификаторы inline и static записывают за списком формальных параметров шаблона, но не перед template. Функции-шаблоны могут быть перегружены другими шаблонными или нешаблонными функциями.

1.1. Генерация конкретных функций по шаблону

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

  1.  если компилятор встретил вызов функции,
  2.  если компилятор встретил операцию взятия адреса функции.

Например, если определен шаблон

template <class T> T f(T x,T y){ return x+y;}

то конкретизация будет производиться в каждом из следующих трех случаев использования функции f:

int i=2, j=3, k=f(i,j);//генерируется функция с аргументами int

long (*pfl)(long,long)=f; //генерируется функция с аргументами long

float (*pff)(float,float)=f; //генерируется функция с аргументами float

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

Этот соответствие устанавливается на основе сопоставления формальных параметров шаблона, используемых в описании аргументов функции с типами фактических параметров вызова функции.

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

Если формальный тип в шаблоне встречается в списке аргументов шаблона функции несколько раз, то каждая следующая привязка должна в точности соответствовать первой привязке типа. При этом недопустимы нетривиальные преобразования и расширения типа. Тривиальными считаются, например, преобразования при присваивании изменяемому объекту какого-то типа значения неизменяемого объекта того же типа. К тривиальным относят также преобразования между типом массива (неизменяемый указатель) и типом соответствующего указателя. Однако преобразования int в unsigned int и наоборот уже нетривиальны (они могут привести к некоторым проблемам).

Пример.

template <class T> T min (T,T);    //прототип

void main(){

unsigned u=15;

min(u,128); min(128,u);}

Оба вызова функции в этом примере приводят к ошибке, так как целые константы имеют по правилам языка тип int (именно int, а не const int).

Однако в следующем примере преобразование тривиально:

template <class T> T first(T a[]) { return a[0];}

void main() {

int a[]={9,8,7}, *b=a;

cout<<first(b)<<endl; }

хотя имя массива имеет тип const int, а переменная b - тип int.

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

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

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

1.2. Порядок разрешения вызова функции

Шаблонная функция может перегружаться при условии, что список формальных параметров каждого ее варианта отличается от остальных либо типами параметров, либо их числом:

template <class T> T f(T,T);

template <class T> T f(T);

template <class T> T f(int, T);

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

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

  1.  Просматриваются все нешаблонные варианты функции с точным сопоставлением типов. Если найдено ровно одно сопоставление – генерируется вызов. Если возможных сопоставлений более одного, то это свидетельствует о неразрешимой неоднозначности при генерации вызова - ошибка.
  2.  Просматриваются все шаблонные варианты функции. Если найдено ровно одно сопоставление, то генерируется вызов. Если возможных сопоставлений более одного то это свидетельствует о неразрешимой неоднозначности при генерации вызова - ошибка.
  3.  Вновь исследуются нешаблонные варианты функции с целью разрешить вызов с помощью приведения типов.

Пример.

template <class T> T f(T,T);    //объявление шаблона

double f(double,double);        //объявление специализированной функции

void main(){

int i;

unsigned int u;

double x,y

f(0,i);           // первый вызов

f(0,u);           // второй вызов

f(x,y);           // третий вызов    }

Первый вызов разрешается по правилу II, так как оба аргумента имеют тип int.

Второй вызов был бы неразрешим, если бы не была бы определена специализированная функция. Здесь работает правило III.

В третьем вызове срабатывает правило I и сразу вызывается специализированная функция, так как сопоставление аргументов точное.

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

long (*pf)(long,long)=f;

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

Ambiguity between 'f(double,double)' and 'f(long,long)'.

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

ЗАДАНИЕ 1

  1.  Какие ошибки допущены в следующих объявлениях?

template <class T, class T> T f(T x);

template <class T1, T2> void f(T1 x);

template <class T>  T  f(int x);

inline template <class T> T f(T x, T y);

  1.  Написать тестовую программу для функции swap и попробовать ее вызовы с разными типами аргументов (значения переменных - числа, символы, строки).
  2.  Написать программу, в которой определяется шаблон для функции max(x,y), возвращающей большее из значений x и y. Написать специализированную версию функции max(char*,char*), возвращающую "большую" из передаваемых ей символьных строк (использовать библиотечную функцию strcmp). В каждой из функций редусмотреть вывод сообщения о том, что вызвана шаблонная или специализированная функция и вывод найденного большего. Проверить работу программы на трех примерах

max('a','1'), max(12,17), max("Hello","World").

Объяснить в каждом случае, какое правило использовалось для реализации вызова.

Шаблоны классов (параметризованные типы).

Шаблоны классов (class templates) являются одним из механизмов С++, реализующих в программах полиморфизм. Их называют также "параметризованными типами" (parameterisized types), "генераторами классов" (class generators) или "родовыми классами" (generic classes).

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

2.1. Описания и объявления шаблонных классов

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

Чтобы подчеркнуть, что данный параметр обозначает тип, соответствующий элемент списка должен начинаться со служебного слова class.

Дополнительные параметры шаблона (не типы) могут использоваться, например, при инициализации объектов класса (в конструкторе) или для других целей.

Пример 1.

В описании класса Test1 параметры T1 и T2 обозначают типы (базовые или созданные пользователем), которые будут конкретизированы при создании экземпляра класса:

template <class T1, class T2> class Test1{

...};

Пример 2.

  1.  Объявление шаблона класса может иметь вид

template <class T1, class T2, int size>  class Test3;

  1.  Описание шаблона класса. Каждый раз, когда в теле шаблона класса его имя используется как спецификация типа, надо указывать список параметров. Это же относится к реализациям функций-членов, если эти описания вынесены за пределы описания класса.

template <class T, int S> class Test{

int i;

T* pT;

public:

Test(){ i=S; pT=new T; } // конструктор использует параметры шаблона

//функции, использующие имя Test как спецификацию типа

Test(Test<T,S>&);    // прототип конструктора копирования

friend ostream& operator<<(ostream& os,Test<T,S>& t)

{ return os<<t.S<<endl;}

};

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

template <class T,int S>

inline Test<T,S>::Test(Test& t)

{ ... }

(в данном случае предполагается реализация конструктора как inline-функции).

В описании конструктора имя Test один раз использовано как имя функции и дважды как имя типа:

  1.  при указании принадлежности конструктора к классу (то есть, к типу);
  2.  при указании типа аргумента.

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

Например, ошибкой будет следующее описание шаблона функции foo:

template <class T,int S> void foo(Test<T,S>& t) { ... }

Однако, если шаблон класса Test не имел бы параметра S, то конструкция шаблона функции была бы допустимой.

Замечание.

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

2.2. Конкретизация шаблона класса

Вне определения шаблона можно использовать только конкретизации шаблонного класса (то есть, с конкретными значениями параметров):

void f(Test<int,2> a){

...

Test<float,1> *pfl;

...  }

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

// объявление шаблона функции

template <class Type> void f(Test<Type>&, Test<int>&);

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

Каждый класс, сгенерированный по шаблону, обладает своими экземплярами статических членов.

Пример.

template <class T> class Test4{

static T a;

static int i;

...

}

Каждый сгенерированный с помощью шаблона класс будет иметь свои собственные статические члены a и i.

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

Пример.

template <class Type> class Test{

  ...

friend void f(int); // дружественная для всех реализаций

friend void f1(Test<Type>);

};

ЗАДАНИЕ 2

  1.  Создать шаблонный класс Array для одномерных массивов элементов произвольного типа Type. Класс должен содержать закрытые поля: size (типа int) - размер массива, и pa - указатель типа Type* на начало массива. Класс должен содержать выделяющие для массива память конструкторы:
  2.  одним параметром типа int - для инициализации size (по умолчанию 10);
  3.  с двумя параметрами - типа int и типа Type* (для инициализации элементов массива).
  4.  Переопределить для класса Array операцию вставки в поток ( << ) таким образом, чтобы на экран выводились размер массива и его элементы.
  5.  Описать и инициализировать некоторые массивы значений типов int, float (длина по своему усмотрению). С их помощью определить и инициализировать два объекта Array с соответствующей конкретизацией (т.е. int, float) и вывести полученные объекты их на экран.
  6.  Создать класс целых чисел Number с одним закрытым полем типа int, конструкторами (определить самим, какие нужны) и переопределенной операцией вставки в поток <<.
  7.  Описать и инициализировать некоторый массив типа Number (длина по своему усмотрению). С его помощью определить и инициализировать объект Array с элементами, объектами класса Number, и вывести объект Array на экран.




1. Петр Дирихле
2. Между ними только секс ложь и непонимание
3. Организация производственной системы предприятия на примере ЗАО Колос
4. Государство и Церковь - взаимодействие или конфликт
5. Лабораторная работа 2 на тему- Работа со строками Выполнил студент группы ВЛ71м Малышко А
6. Оценка стратегического состояния предприятия методом SPSE
7. на тему- ldquo;Генетически модифицированные организмы в пищеrdquo; Подготовил студент гр П1
8. 2 сем Основное преимущество Webпочты по сравнению с обычной электронной почтой заключается
9. тематики специальность 010500
10. Успешная отработка практических вопросов студентами возможна только при надлежащей организации подготов