Главная Случайная страница


Полезное:

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


Категории:

АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника






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





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

 

template < список_параметров_шаблона >

 

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

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

Пример:

 

// Описание шаблона функции

template <class X>

X min (X a, X b)

{

return a<b? a: b;

}

 

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

Пример:

 

...

// Использование шаблона функции

int m = min (1, 2);

...

 

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

 

int min (int a, int b)

{

return a<b? a: b;

}

 

В списке параметров шаблона слово class может также относится к обычному типу данных. Таким образом, список параметров шаблона <class T> просто означает, что Т представляет собой тип, который будет задан позднее. Так как Т является параметром, обозначающим тип, шаблоны иногда называют параметризованными типами.

Например, описание шаблона функции

 

template <class T>

T toPower (T base, int exponent)

{

T result = base;

if (exponent==0) return (T)1;

if (exponent<0) return (T)0;

while (--exponent) result *= base;

return result;

}

 

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

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

Пример:

 

int i = toPower (10, 3);

long l = toPower (1000L, 4);

double d = toPower (1e5, 5);

 

В первом примере Т становится типом int, во втором - long. Наконец, в третьем примере Т становится типом double. Следующий пример приведет к ошибке компиляции, так как в нем используются разные типы данных:

 

int i = toPower (1000L, 4);

 

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

Основные свойства параметров шаблона:

1. Имена параметров шаблона должны быть уникальными во всем определении шаблона.

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

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

 

template <class type1, class type2>

 

Соответственно, неверен заголовок:

 

template <class type1, type2, type3>

 

4. Недопустимо использовать в заголовке шаблона параметры с одинаковыми именами.

 

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

Требования к фактическим параметрам шаблона. Рассмотрим шаблон из примера функции toPower(). Шаблон функции toPower() может быть использован почти для любого типа данных. Предостережение "почти" проистекает из характера операций, выполняемых над параметром base и переменной result в теле функции toPower(). Какой бы тип мы не использовали в функции toPower(), эти операции для нее должны быть определены. В противном случае компилятор не будет знать, что ему делать. Вот список действий, выполняемых в функции toPower() с переменными base и result:

 

1. T result = base;

2. return (T)1;

3. return (T)0;

4. result *= base;

5. return result;

 

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

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

2 действия 2 и 3 преобразуют значения типа int в объект типа Т, поэтому класс Т должен содержать конструктор с параметром типа int, поскольку именно таким способом в классах реализуется преобразование к классовым типам,

3 действие 4 использует операцию *= над типом Т, поэтому класс должен содержать собственную функцию-operator *=().

4 действие 5 предполагает, что в типе T предусмотрена возможность построения безопасной копии возвращаемого объекта (см. конструктор копирования).

Схема такого класса выглядит следующим образом:

 

class T

{

public:

T (const T &base); // конструктор копирования

T (int i); //приведение int к Т

operator *= (T base);

//... прочие методы

}

 

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

Так как компилятор генерирует экземпляры шаблонов функций согласно типам, заданным при их вызовах, то критическим моментом является передача корректных типов, особенно если шаблон функции имеет два или более параметров. Хорошим примером является классическая функция max():

 

template <class T>

T max (T a, T b)

{

return a > b? a: b;

}

 

Функция max() будет работать правильно, если оба ее аргумента имеют один и тот же тип:

 

int i = max (1, 2);

double d = max (1.2, 3.4);

 

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

 

int i = max ((int)'a', 100);

 

Вторая возможность - это явно объявить версию экземпляра шаблона функции перед ее вызовом:

 

int max (int, int);

int j = max ('a', 100);

 

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

 

template <class T1, class T2>

T1 max (T1 a, T2 b)

{

return a > (T1)b? a: (T1)b;

}

 

Использование этой новой версии max() не приведет к неоднозначности в случае использования двух различных типов. Например, если написать

max ('a', 100);

то компилятор будет использовать два заданных (посредством аргументов типа) и построит версию функции max() с заголовком

 

char max (char, int);

 

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

 

max ('a', 100)

дает значение типа char, в то время как

max (100, 'a')

передает в вызывающую программу int.

Date: 2015-12-12; view: 502; Нарушение авторских прав; Помощь в написании работы --> СЮДА...



mydocx.ru - 2015-2024 year. (0.006 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию