Многие владельцы Android девайсов от Samsung жалуются, что у них возникают...
Вы можете создать прототип шаблона функции в виде его предварительного объявления. Такое объявление информирует компилятор о наличии шаблона, а также сообщает об ожидаемых параметрах. Например, прототип шаблона функции Sort будет выглядеть так:
template
Имена формальных параметров шаблона могут не совпадать в предварительном объявлении и определении шаблона. Так, например, в следующем фрагменте и прототип шаблона, и определение шаблона относятся к одной и той же функции:
template
template
Type max(Type a, Type b)
if (a > b) return a; else return b;
Использование шаблона функции
Шаблон функции описывает, как конкретная функция может быть построена на основании одного или нескольких фактических типов. Компилятор автоматически создает представитель тела функции для указанных в вызове типов. Такой процесс называется конкретизацией . Он происходит при вызове шаблонной функции.
Например, в следующем примере функция min() конкретизируется дважды: один раз типом int и один раз типом double:
template
Type min(Type a, Type b)
if (a < b) return a; else return b;
int x = 4, y = 5, z;
double t = 6.56, r = 3.07, p;
Специализация шаблонов функции
Специализированная функция шаблона – это обычная функция, имя которой совпадает с именем функции в шаблоне, но которая определяется для параметров специфических типов. Специализированные функции шаблона определяют в том случае, когда обобщенный шаблон не годится для некоторого типа данных. Например, функция шаблона min
template
Type min(Type a, Type b)
if (a < b) return a; else return b;
не может применяться для строк (для типа char*) , так как генерируемый компилятором код будет просто сравнивать их положение в памяти (адреса). Для корректного сравнения строк можно определить специализированную функцию:
char* min(char* s1, char* s2)
if (strcmp(s1,s2)>0) return s2; else return s1;
Тогда обращаться к такой функции можно так же, как и к функции шаблона:
int i1 = 3, i2 = 5;
cout << “max int = ” << max(i1, i2) << endl;
char* s1 = “Golden Eagle”;
char* s2 = “Perigrine Falcon”;
cout << “max str = “ << max(s1, s2) << endl;
Шаблоны классов
Шаблон класса дает обобщенное определение семейства классов, использующее произвольные типы или константы. Шаблон определяет данные-члены шаблона и функции-члены шаблона . После определения шаблона класса можно предписать компилятору генерировать на его основе новый класс для конкретного типа или константы.
Синтаксис шаблона класса
template <<список аргументов шаблона>>
class <имя класса>
<тело класса>
За ключевым словом template следуют один или несколько аргументов (параметров), заключенных в угловые скобки и отделяемых друг от друга запятыми. Каждый аргумент может представлять собой ключевое слово class, за которым следует идентификатор, обозначающий параметризованный тип. Список аргументов шаблона не может быть пустым.
Затем следует определение класса. Оно аналогично определению обычного класса, за исключением того, что использует список аргументов шаблона.
Параметры шаблона, состоящие из ключевого слова class и следующего за ним идентификатора, часто называют параметрами типа . Другими словами, они информируют компилятор, что шаблон предполагает тип в качестве аргумента.
Функция-шаблон определяет общий набор операций, который будет применен к данным различных типов. Используя этот механизм, можно применять некоторые общие алгоритмы к широкому кругу данных. Как известно, многие алгоритмы логически одинаковы вне зависимости от типа данных, с которыми они оперируют. Например, алгоритм быстрой сортировки Quicksort один и тот же и для массива целых чисел, и для массива чисел с плавающей запятой. Отличается только тип данных, подлежащих сортировке. При помощи создания функции-шаблона (generic function) можно определить сущность алгоритма безотносительно к типу данных. После этого компилятор автоматически генерирует корректный код для того типа данных, для которого создается данная конкретная реализация функции на этапе компиляции. По существу, когда создается функция- шаблон, создается функция, которая может автоматически перегружать сама себя.
Функции-шаблоны создаются с использованием ключевого слова template (шаблон). Обычное значение слова «шаблон» достаточно полно отражает его использование в С++. Шаблон используется для создания каркаса функции, оставляя компилятору реализацию подробностей. Общая форма функции-шаблона имеет следующий вид:
template
{
// тело функции
}
Здесь птип является параметром-типом, «держателем места» (placeholder) для имени типа данных, которое используется функцией. Этот параметр-тип может быть использован в определении функции. Однако это только «держатель места», который будет автоматически заменен компилятором на фактический тип данных во время создания конкретной версии функции.
Ниже приведен короткий пример, в котором создается функция-шаблон, имеющая два параметра. Эта функция меняет между собой величины значений этих параметров. Поскольку общий процесс обмена значениями между двумя переменными не зависит от их типа, то он естественным способом может быть реализован с помощью функции-шаблона.
// пример шаблона функции
#include
// шаблон функции
template
{
X temp;
temp = a;
a = b;
b = temp;
}
int main()
{
int i=10, j = 20;
float x=10.1, у= 23.3;
char a="x", b="z";
cout << "Original i, j: " << i << " " << j << endl;
cout << "Original x, y: " << x << " " << у << endl;
cout << "Original a, b: " << a << " " << b << endl;
swap(i, j); // обмен целых
swap(x, у); // обмен вещественных значений
swap(a, b); // обмен символов
cout << "Swapped i, j: " << i << " " << j << endl;
cout << "Swapped x, y: " << x << " " << у << endl;
cout << "Swapped a, b: " << a << " " << b << endl;
return 0;
}
Рассмотрим эту программу более внимательно. Строка
Template
Указывает компилятору, что создается шаблон. Здесь X - шаблон типа, используемый в качестве параметра-типа. Далее следует объявление функции swap() с использованием типа данных X для тех параметров, которые будут обмениваться значениями. В функции main() функция swap() вызывается с передачей ей данных трех различных типов: целых чисел, чисел с плавающей запятой и символов. Поскольку функция swap() является функцией-шаблоном, то компилятор автоматически создаст три разные версии функции swap() - одну для работы с целыми числами, другую для работы с числами с плавающей запятой и, наконец, третью для работы с переменными символьного типа.
До настоящего момента обсуждались вопросы построения шаблонных классов на основе предопределенных (включенных в состав библиотеки классов) шаблонов классов. В этом разделе на простом примере обсуждается техника объявления собственных шаблонов классов и шаблонов функций.
Шаблонный класс обеспечивает стандартную реализацию дополнительной функциональности на основе ранее объявленных подстановочных классов.
Эта дополнительная функциональность может накладывать дополнительные ограничения на подстановочный класс . Например, для успешной работы объекта шаблонного класса подстановочный класс должен наследовать определенному интерфейсу. Иначе функциональность шаблонного класса просто невозможно будет реализовать.
Для формирования ограничений на подстановочные классы в C# используется механизм ограничителей параметров шаблона - он вводится при объявлении шаблона с помощью ключевого слова where , за которым могут располагаться имя параметра типа и список типов класса или интерфейса либо конструктор – ограничение new() :
Using System;
using System.Collections;
using System.Collections.Generic;
namespace PatternArrays
{
//========== Это заголовок шаблона класса W ==========
// Шаблон класса своими руками. T – параметр шаблона.
// Шаблонный класс – это класс-шаблон, который детализируется
// подстановочным классом.
// При создании шаблонного класса вхождения параметра шаблона
// (в данном случае это T) замещаются именем подстановочного
// класса. Разработчик шаблона класса может выдвигать требования
// относительно характеристик подстановочного класса.
// Для этого используются специальные языковые конструкции,
// называемые ОГРАНИЧИТЕЛЯМИ ПАРАМЕТРА ШАБЛОНА.
// ОГРАНИЧИТЕЛЬ ПАРАМЕТРА ШАБЛОНА формулирует требования для
// подстановочного класса.
class W
Пример использования шаблонов: сортировка
Старая задача, новые решения с использованием предопределенных шаблонов классов и интерфейсов...
Using System;
using System.Collections;
using System.Collections.Generic;
namespace PatternArrays
{
// Данные для массива элементов.
// Подлежат сортировке в составе шаблонного массива методом Sort.
class Points
{
public int x;
public int y;
public Points(int key1, int key2)
{
x = key1;
y = key2;
}
// Вычисляется расстояние от начала координат.
public int R
{
get
{
return (int)(Math.Sqrt(x * x + y * y));
}
}
}
// ...ШАБЛОННЫЙ КОМПАРЕР на основе шаблона интерфейса...
class myComparer: IComparer
Nullable-типы
Nullable-типы (простые Nullable-типы) представляют собой расширения простых типов. Их объявления принадлежат пространству имен System.Nullable .
Это шаблонные типы, то есть типы, построенные в результате детализации шаблонов. Шаблон Nullable<> используется для расширения простых типов, которые по своей сути являются структурами. Для обозначения Nullable шаблонных (построенных на основе шаблона) типов используются две нотации.
При создании функций иногда возникают ситуации, когда две функции выполняют одинаковую обработку, но работают с разными типами данных (например, одна использует параметры типа int, а другая типа float). Вы уже знаете из урока 13, что с помощью механизма перегрузки функций можно использовать одно и то же имя для функций, выполняющих разные действия и имеющих разные типы параметров. Однако, если функции возвращают значения разных типов, вам следует использовать для них уникальные имена (см. примечание к уроку 13). Предположим, например, что у вас есть функция с именем тах, которая возвращает максимальное из двух целых значений. Если позже вам потребуется подобная функция, которая возвращает максимальное из двух значений с плавающей точкой, вам следует определить другую функцию, например fmax. Из этого урока вы узнаете, как использовать шаблоны C++ для быстрого создания функций, возвращающих значения разных типов. К концу данного урока вы освоите следующие основные концепции:
- Шаблон определяет набор операторов, с помощью которых ваши программы позже могут создать несколько функций.
- Программы часто используют шаблоны функций для быстрого определения нескольких функций, которые с помощью одинаковых операторов работают с параметрами разных типов или имеют разные типы возвращаемых значений.
- Шаблоны функций имеют специфичные имена, которые соответствуют имени функции, используемому вами в программе.
- После того как ваша программа определила шаблон функции, она в дальнейшем может создать конкретную функцию, используя этот шаблон для задания прототипа, который включает имя данного шаблона, возвращаемое функцией значение и типы параметров.
- В процессе компиляции компилятор C++ будет создавать в вашей программе функции с использованием типов, указанных в прототипах функций, которые ссылаются на имя шаблона.
Шаблоны функций имеют уникальный синтаксис, который может быть на первый взгляд непонятен. Однако после создания одного или двух шаблонов вы обнаружите, что реально их очень легко использовать.
СОЗДАНИЕ ПРОСТОГО ШАБЛОНА ФУНКЦИИ
Шаблон функции определяет типонезависимую функцию. С помощью такого шаблона ваши программы в дальнейшем могут определить конкретные функции с требуемыми типами. Например, ниже определен шаблон для функции с именем тах, которая возвращает большее из двух значений:
template
Т mах(Т а, Т b) {
if (а > b) return(а);
else return(b);
}
Буква T данном случае представляет собой общий тип шаблона. После определения шаблона внутри вашей программы вы объявляете прототипы функций для каждого требуемого вам типа. В случае шаблона тах следующие прототипы создают функции типа float и int.
float max(float, float);
int max(int, int);
Когда компилятор C++ встретит эти прототипы, то при построении функции он заменит тип шаблона T указанным вами типом. В случае с типом float функция тах после замены примет следующий вид:
template
Т max(Т а, Т b)
{
if (a > b) return(а) ;
else return(b);
}float max(float a, float b)
{
if (a > b) return(a) ;
else return(b);
}
Следующая программа МАХ_ТЕМР.СРР использует шаблон тах для создания функции типа int и float.
#include
template
Т mах(Т а, Т b) {
if (a > b) return(a);
else return(b);
}float max(float, float);
int max(int, int);
{
cout << «Максимум 100 и 200 равен » << max(100, 200) << endl;
cout << «Максимум 5.4321 и 1.2345 равен » << max(5.4321, 1.2345) << endl;
}
В процессе компиляции компилятор C++ автоматически создает операторы для построения одной функции, работающей с типом int, и второй функции, работающей с типом float. Поскольку компилятор C++ управляет операторами, соответствующими функциям, которые вы создаете с помощью шаблонов, он позволяет вам использовать одинаковые имена для функций, которые возвращают значения разных типов. Вы не смогли бы это сделать, используя только перегрузкуфункций, как обсуждалось в уроке 13.
Использование шаблонов функций
По мере того как ваши программы становятся более сложными, возможны ситуации, когда вам потребуются подобные функции, выполняющие одни и те же операции, но с разными типами данных. Шаблон функции позволяет вашим программам определять общую, или типонезависимую, функцию. Когда программе требуется использовать функцию для определенного типа, например int или float, она указывает прототип функции, который использует имя шаблона функции и типы возвращаемого значения и параметров. В процессе компиляции C++ создаст соответствующую функцию. Создавая шаблоны, вы уменьшаете количество функций, которые должны кодировать самостоятельно, а ваши программы могут использовать одно и то же имя для функций,выполняющих определенную операцию, независимо от возвращаемого функцией значения и типов параметров.
ШАБЛОНЫ, КОТОРЫЕ ИСПОЛЬЗУЮТ НЕСКОЛЬКО ТИПОВ
Предыдущее определение шаблона для функции max использовало единственный общий тип Т. Очень часто в шаблоне функции требуется указать несколько типов. Например, следующие операторы создают шаблон для функции show_array, которая выводит элементы массива. Шаблон использует тип Т для определения типа массива и тип Т1 для указания типа параметра count:
template
{
T1 index;
for (index =0; index < count; index++) cout << array << ‘ ‘;
cout << endl;
}
Как и ранее, программа должна указать прототипы функций для требуемых типов:
void show_array(int *, int);
void show_array(float *, unsigned);
Следующая программа SHOW_TEM.CPP использует шаблон для создания функций, которые выводят массивы типа int и типа float.
#include
template
void show_array(T *array,T1 count) {
T1 index;
for (index =0; index < count; index++) cout << array “ ‘ ‘;
cout << endl;
}void show_array(int *, int);
void show_array(float *, unsigned);
{
int pages = { 100, 200, 300, 400, 500 };
float pricesH = { 10.05, 20.10, 30.15 };
show_array(pages, 5);
show_array(prices, 3);
}Шаблоны и несколько типов
По мере того как шаблоны функций становятся более сложными, они могут обеспечить поддержку нескольких типов. Например, ваша программа может создать шаблон для функции с именем array_sort, которая сортирует элементы массива. В данном случае функция может использовать два параметра: первый, соответствующий массиву, и второй, соответствующий количеству элементов массива. Если программа предполагает, что массив никогда не будет содержать более 32767 значений она может использовать тип int для параметра размера массива. Однако более универсальный шаблон мог бы предоставить программе возможность указать свой собственный тип этого параметра, как показано ниже:
template
void array_sort(T array, T1 elements) {
// операторы
}С помощью шаблона array_sort программа может создать функции которые сортируют маленькие массивы типа float (менее 128 элементов) и очень большие массивы типа int, используя следующие прототипы:
void array_sort(float, char);
void array_sort(int, long);
ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ
Как вы уже знаете, использование шаблонов функций уменьшает объем программирования, позволяя компилятору C++ генерировать операторы для функций, которые отличаются только типами возвращаемых значений и параметров. Из урока 30 вы узнаете, как использовать шаблоны для создания типонезависимых, или общих, классов. До изучения урока 30 убедитесь, что вы освоили следующие основные концепции:
- Шаблоны функций позволяют вам объявлять типонезависимые, или общие, функции.
- Когда вашей программе требуется использовать функцию с определенными типами данных, она должна указать прототип функции, который определяет требуемые типы.
- Когда компилятор C++ встретит такой прототип функции, он создаст операторы, соответствующие этой функции, подставляя требуемые типы.
- Ваши программы должны создавать шаблоны для общих функций, которые работают с отличающимися типами. Другими словами, если вы используете с какой-либо функцией только один тип, нет необходимости применять шаблон.
- Если функция требует несколько типов, шаблон просто назначает каждому типу уникальный идентификатор, например Т, T1 и Т2. Позже в процессе компиляции компилятор C++ корректно назначит типы, указанные вами в прототипе функции.
Урок 29. Использование шаблонов функций
При создании функций иногда возникают ситуации, когда две функции выполняют одинаковую обработку, но работают с разными типами данных (например, одна использует параметры типа int, а другая типа float). Вы уже знаете из урока 13, что с помощью механизма перегрузки функций можно использовать одно и то же имя для функций, выполняющих разные действия и имеющих разные типы параметров. Однако, если функции возвращают значения разных типов, вам следует использовать для них уникальные имена (см. примечание к уроку 13). Предположим, например, что у вас есть функция с именем тах, которая возвращает максимальное из двух целых значений. Если позже вам потребуется подобная функция, которая возвращает максимальное из двух значений с плавающей точкой, вам следует определить другую функцию, например fmax. Из этого урока вы узнаете, как использовать шаблоны C++ для быстрого создания функций, возвращающих значения разных типов. К концу данного урока вы освоите следующие основные концепции:
Шаблон определяет набор операторов, с помощью которых ваши программы позже могут создать несколько функций.
Программы часто используют шаблоны функций для быстрого определения нескольких функций, которые с помощью одинаковых операторов работают с параметрами разных типов или имеют разные типы возвращаемых значений.
Шаблоны функций имеют специфичные имена, которые соответствуют имени функции, используемому вами в программе.
После того как ваша программа определила шаблон функции, она в дальнейшем может создать конкретную функцию, используя этот шаблон для задания прототипа, который включает имя данного шаблона, возвращаемое функцией значение и типы параметров.
В процессе компиляции компилятор C++ будет создавать в вашей программе функции с использованием типов, указанных в прототипах функций, которые ссылаются на имя шаблона.
Шаблоны функций имеют уникальный синтаксис, который может быть на первый взгляд непонятен. Однако после создания одного или двух шаблонов вы обнаружите, что реально их очень легко использовать.
СОЗДАНИЕ ПРОСТОГО ШАБЛОНА ФУНКЦИИ
Шаблон функции определяет типонезависимую функцию. С помощью такого шаблона ваши программы в дальнейшем могут определить конкретные функции с требуемыми типами. Например, ниже определен шаблон для функции с именем тах, которая возвращает большее из двух значений:
template
{ if (а > b) return(а); else return(b); }
Буква T данном случае представляет собой общий тип шаблона. После определения шаблона внутри вашей программы вы объявляете прототипы функций для каждого требуемого вам типа. В случае шаблона тах следующие прототипы создают функции типа float и int.
float max(float, float); int max(int, int);
Когда компилятор C++ встретит эти прототипы, то при построении функции он заменит тип шаблона T указанным вами типом. В случае с типом float функция тах после замены примет следующий вид:
template
{ if (a > b) return(а) ; else return(b); }
float max(float a, float b)
{ if (a > b) return(a) ; else return(b); }
Следующая программа МАХ_ТЕМР.СРР использует шаблон тах для создания функции типа int и float.
#include
template
{ if (a > b) return(a); else return(b); }
float max(float, float);
int max(int, int);
{ cout << "Максимум 100 и 200 равен " << max(100, 200) << endl; cout << "Максимум 5.4321 и 1.2345 равен " << max(5.4321, 1.2345) << endl; }
В процессе компиляции компилятор C++ автоматически создает операторы для построения одной функции, работающей с типом int, и второй функции, работающей с типом float. Поскольку компилятор C++ управляет операторами, соответствующими функциям, которые вы создаете с помощью шаблонов, он позволяет вам использовать одинаковые имена для функций, которые возвращают значения разных типов. Вы не смогли бы это сделать, используя только перегрузку функций, как обсуждалось в уроке 13.
Использование шаблонов функций
По мере того как ваши программы становятся более сложными, возможны ситуации, когда вам потребуются подобные функции, выполняющие одни и те же операции, но с разными типами данных. Шаблон функции позволяет вашим программам определять общую, или типонезависимую, функцию. Когда программе требуется использовать функцию для определенного типа, например int или float, она указывает прототип функции, который использует имя шаблона функции и типы возвращаемого значения и параметров. В процессе компиляции C++ создаст соответствующую функцию. Создавая шаблоны, вы уменьшаете количество функций, которые должны кодировать самостоятельно, а ваши программы могут использовать одно и то же имя для функций, выполняющих определенную операцию, независимо от возвращаемого функцией значения и типов параметров.
ШАБЛОНЫ, КОТОРЫЕ ИСПОЛЬЗУЮТ НЕСКОЛЬКО ТИПОВ
Предыдущее определение шаблона для функции max использовало единственный общий тип Т. Очень часто в шаблоне функции требуется указать несколько типов. Например, следующие операторы создают шаблон для функции show_array, которая выводит элементы массива. Шаблон использует тип Т для определения типа массива и тип Т1 для указания типа параметра count:
template
< count; index++) cout << array << " "; cout << endl; }
Как и ранее, программа должна указать прототипы функций для требуемых типов:
void show_array(int *, int); void show_array(float *, unsigned);
Следующая программа SHOW_TEM.CPP использует шаблон для создания функций, которые выводят массивы типа int и типа float.
#include
template
{ T1 index; for (index =0; index < count; index++) cout << array “ " "; cout << endl; }
void show_array(int *, int);
void show_array(float *, unsigned);
{ int pages = { 100, 200, 300, 400, 500 }; float pricesH = { 10.05, 20.10, 30.15 }; show_array(pages, 5); show_array(prices, 3); }
Шаблоны и несколько типов
По мере того как шаблоны функций становятся более сложными, они могут обеспечить поддержку нескольких типов. Например, ваша программа может создать шаблон для функции с именем array_sort, которая сортирует элементы массива. В данном случае функция может использовать два параметра: первый, соответствующий массиву, и второй, соответствующий количеству элементов массива. Если программа предполагает, что массив никогда не будет содержать более 32767 значений она может использовать тип int для параметра размера массива. Однако более универсальный шаблон мог бы предоставить программе возможность указать свой собственный тип этого параметра, как показано ниже:
template
{ // операторы }
С помощью шаблона array_sort программа может создать функции которые сортируют маленькие массивы типа float (менее 128 элементов) и очень большие массивы типа int, используя следующие прототипы:
void array_sort(float, char); void array_sort(int, long);
ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ
Как вы уже знаете, использование шаблонов функций уменьшает объем программирования, позволяя компилятору C++ генерировать операторы для функций, которые отличаются только типами возвращаемых значений и параметров. Из урока 30 вы узнаете, как использовать шаблоны для создания типонезависимых, или общих, классов. До изучения урока 30 убедитесь, что вы освоили следующие основные концепции:
Шаблоны функций позволяют вам объявлять типонезависимые, или общие, функции.
Когда вашей программе требуется использовать функцию с определенными типами данных, она должна указать прототип функции, который определяет требуемые типы.
Когда компилятор C++ встретит такой прототип функции, он создаст операторы, соответствующие этой функции, подставляя требуемые типы.
Ваши программы должны создавать шаблоны для общих функций, которые работают с отличающимися типами. Другими словами, если вы используете с какой-либо функцией только один тип, нет необходимости применять шаблон.
Если функция требует несколько типов, шаблон просто назначает каждому типу уникальный идентификатор, например Т, T1 и Т2. Позже в процессе компиляции компилятор C++ корректно назначит типы, указанные вами в прототипе функции.