C ++

Как использовать шаблоны C ++

Как использовать шаблоны C ++

Вступление

В базовом программировании на C ++ тип данных e.грамм., int или char, должны быть указаны в объявлении или определении. Такое значение, как 4, 22 или -5, является целым числом. Значение, такое как 'A', 'b' или 'c', является символом. Механизм шаблонов позволяет программисту использовать универсальный тип для набора фактических типов. Например, программист может решить использовать идентификатор T для int или char. Алгоритм C ++ может иметь более одного универсального типа. С, скажем, T для int или char, U может обозначать тип с плавающей запятой или указатель. Класс, такой как строковый или векторный класс, подобен типу данных, а созданные экземпляры объектов подобны значениям типа данных, который является указанным классом. Таким образом, механизм шаблонов также позволяет программисту использовать идентификатор универсального типа для набора классов.

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

Типы

Скалярный

Скалярные типы: void, bool, char, int, float и pointer.

Классы как типы

Конкретный класс можно рассматривать как тип, а его объекты - как возможные значения.

Универсальный тип представляет собой набор скалярных типов. Список скалярных типов обширен. Например, тип int имеет другие связанные типы, такие как short int, long int и т. Д. Универсальный тип также может представлять набор классов.

Переменная

Пример объявления и определения шаблона следующий:

шаблон
Т пи = 3.14;

Прежде чем продолжить, обратите внимание, что этот вид операторов не может появляться в функции main () или в любой области блока. Первая строка - это объявление заголовка шаблона с выбранным программистом универсальным именем типа, T. Следующая строка - это определение идентификатора pi, который относится к универсальному типу T. Точность того, является ли T int или float или каким-либо другим типом, может быть достигнута в функции C ++ main () (или какой-либо другой функции). Такая точность будет сделана с переменной pi, а не T.

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

Следующий оператор может быть записан в main () или в любой другой функции:

cout << pi << '\n';

И функция отобразит 3.14. Выражение пи определяет точный тип T для переменной pi. Специализация определяет конкретный тип данных для параметра шаблона. Создание экземпляра - это внутренний процесс C ++ создания определенного типа, такого как float, в данном случае. Не путайте создание экземпляра параметра шаблона и создание экземпляра класса. В теме шаблона многие типы данных могут иметь одно общее имя типа, тогда как многие классы могут иметь одно общее имя класса. Однако общее имя класса для классов просто упоминается как класс, а не как имя класса. Кроме того, значение относится к типу данных, например int, как созданный объект относится к классу, например к классу String.

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

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

Тип по умолчанию

Если в специализации не указан тип, предполагается тип по умолчанию. Итак, из следующего выражения:

шаблон
U pi = "любовь";
отображение из:
cout << pi<> << '\n';

«любовь» к постоянному указателю на char. Обратите внимание в объявлении, что U = const char *. Угловые скобки будут пустыми при специализации (тип не указан); фактический тип считается константным указателем на char, тип по умолчанию. Если бы при специализации требовался какой-то другой тип, то имя типа записывалось бы в угловых скобках. Если для специализации требуется тип по умолчанию, повторение типа в угловых скобках необязательно, i.е., угловые скобки можно оставить пустыми.

Примечание: тип по умолчанию все еще можно изменить при специализации, установив другой тип.

структура

В следующем примере показано, как параметр шаблона можно использовать со структурой:

шаблон структура возрастов

Т Джон = 11;
Т Петр = 12;
Т Мэри = 13;
Т Радость = 14;
;

Это возраст учащихся класса (класса). Первая строка - это объявление шаблона. Тело в фигурных скобках - это фактическое определение шаблона. Возраст можно вывести в функции main () следующим образом:

Возраст 7 класс;
cout << grade7.John << " << grade7.Mary << '\n';

Результат: 11 13. Первый оператор здесь выполняет специализацию. Обратите внимание, как это было сделано. Он также дает имя для объекта структуры: grade7. Второй оператор имеет обычные выражения объекта структуры. Структура похожа на класс. Здесь Ages похож на имя класса, а grade7 - это объект класса (структура).

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

шаблон структура возрастов

Т Джон = 11;
U Питер = 12.3;
Т Мэри = 13;
U радость = 14.6;
;

Соответствующий код для функции main () выглядит следующим образом:

Возраст 7 класс;
cout << grade7.John << " << grade7.Peter << '\n';

Результат: 11 12.3. При специализации порядок типов (аргументов) должен соответствовать порядку универсальных типов в объявлении.

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

шаблон структура возрастов

Т Джон;
У Питера;
Т Мэри;
U Joy;
;
Возраст grade7 = 11, 12.3, 13, 14.6;

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

Не тип

Примеры типов, не относящихся к данным, включают int, указатель на объект, указатель на функцию и типы auto. Есть и другие нетипы, которые в этой статье не рассматриваются. Нетип подобен неполному типу, значение которого дается позже и не может быть изменено. В качестве параметра он начинается с определенного не-типа, за которым следует идентификатор. Значение идентификатора дается позже, при специализации, и не может быть изменено снова (как константа, значение которой дается позже). Следующая программа иллюстрирует это:

#включать
используя пространство имен std;
шаблон структура возрастов

Т Джон = N;
U Питер = 12.3;
Т Мэри = N;
U радость = 14.6;
;
int main ()

Возраст 7 класс;
cout << grade7.John << " << grade7.Joy << '\n';
возврат 0;

При специализации первый тип, int, в угловых скобках больше для формальности, чтобы убедиться, что количество и порядок параметров соответствуют количеству и порядку типов (аргументов). Значение N было присвоено при специализации. Результат: 11 14.6.

Частичная специализация

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

#включать
используя пространство имен std;
// базовый шаблонный класс
шаблон
структура возрастов

;
// частичная специализация
шаблон
структура возрастов

Т1 Джон = 11;
float Peter = 12.3;
Т1 Мэри = 13;
плавать Радость = 14.6;
;
int main ()

Возраст 7 класс;
cout << grade7.John << " << grade7.Joy << '\n';
возврат 0;

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

Соответствующий код в функции main () может быть следующим:

Возраст 7 класс;
cout << grade7.John << " << grade7.Joy << '\n';

Результат: 11 14.6.

Пакет параметров шаблона

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

#включать
используя пространство имен std;
шаблон структура возрастов

int John = 11;
float Peter = 12.3;
int Mary = 13;
плавать Радость = 14.6;
;
int main ()

Возраст gradeB;
cout << gradeB.John << " << gradeB.Mary << '\n';
Возраст gradeC;
cout << gradeC.Peter << " << gradeC.Joy << '\n';
Возраст GradeD;
cout << gradeD.John << " << gradeD.Joy << '\n';
Возраст <> gradeA; // как по умолчанию
cout << gradeA.John << " << gradeA.Joy << '\n';
возврат 0;

Результат:

11 13
12.3 14.6
11 14.6
11 14.6

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

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

#включать
используя пространство имен std;
шаблон void func (T no, U cha, const char * str)

cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';

int main ()

func (12, '$', «500»);
возврат 0;

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

В магазине 12 книг стоимостью 500 долларов.

Отделение от прототипа

Определение функции можно отделить от ее прототипа, как показано в следующей программе:

#включать
используя пространство имен std;
шаблон void func (T no, U cha, const char * str);
шаблон void func (T no, U cha, const char * str)

cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';

int main ()

func (12, '$', «500»);
возврат 0;

Примечание: объявление шаблона функции не может появляться в функции main () или в любой другой функции.

Перегрузка

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

#включать
используя пространство имен std;
шаблон void func (T no, U cha, const char * str)

cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';

шаблон void func (T нет, const char * str)

cout << "There are " << no << " books worth $" << str << " in the store." << '\n';

int main ()

func (12, '$', «500»);
func (12, «500»);
возврат 0;

Результат:

В магазине 12 книг стоимостью 500 долларов.

В магазине 12 книг стоимостью 500 долларов.

Шаблоны классов

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

#включать
используя пространство имен std;
класс TheCla

общественность:
int num;
static char ch;
void func (char cha, const char * str)

cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

статическая пустота весело (char ch)

если (ch == 'a')
cout << "Official static member function" << '\n';

;
int main ()

TheCla obj;
объект.число = 12;
объект.func ('$', «500»);
возврат 0;

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

В магазине 12 книг стоимостью 500 долларов.

Следующая программа представляет собой указанную выше программу с объявлением заголовка шаблона:

#включать
используя пространство имен std;
шаблон класс TheCla

общественность:
T num;
статический U ч;
void func (U cha, const char * str)

cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

статическая пустота веселье (U ch)

если (ch == 'a')
cout << "Official static member function" << '\n';

;
int main ()

TheCla obj;
объект.число = 12;
объект.func ('$', «500»);
возврат 0;

Вместо слова typename в списке параметров шаблона можно использовать слово class. Обратите внимание на специализацию в объявлении объекта. Результат все тот же:

В магазине 12 книг стоимостью 500 долларов.

Разделительная декларация

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

шаблон class TheCla;
шаблон класс TheCla

общественность:
T num;
статический U ч;
void func (U cha, const char * str)

cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

статическая пустота веселье (U ch)

если (ch == 'a')
cout << "Official static member function" << '\n';

;

Работа со статическими членами

В следующей программе показано, как получить доступ к статическому члену данных и статической функции-члену:

#включать
используя пространство имен std;
шаблон класс TheCla

общественность:
T num;
статический U ч;
void func (U cha, const char * str)

cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

статическая пустота веселье (у ча)

если (ch == 'a')
cout << "Official static member function" << cha << '\n';

;
шаблон U TheCla:: ch = 'а';
int main ()

TheCla::веселье('.');
возврат 0;

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

Официальная статическая функция-член.

Компиляция

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

Заключение

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

OpenTTD против Simutrans
Создание собственного транспортного симулятора может быть увлекательным, расслабляющим и чрезвычайно увлекательным занятием. Вот почему вам нужно попр...
Учебник OpenTTD
OpenTTD - одна из самых популярных бизнес-симуляторов. В этой игре вам нужно создать замечательный транспортный бизнес. Тем не менее, вы начнете в нач...
SuperTuxKart для Linux
SuperTuxKart - отличная игра, созданная для того, чтобы бесплатно познакомить вас с Mario Kart в вашей системе Linux. Играть в нее довольно сложно и в...